代码改变世界

Effective C# 学习笔记(三十九) 使用Dynamic处理范型参数的运行时类型

2011-07-29 19:35  小郝(Kaibo Hao)  阅读(387)  评论(0编辑  收藏  举报

由于Enumerable.Cast<T>方法,其对T类型所知范围仅限于Sytem.Object类型的那些方法,所以对于T类型的特殊类型转换方法(无论是Implicit还是Explicit的)其都不会理睬。所以在使用运行时类型枚举转换时请注意使用适当的方法。

 

先看一段代码:

public class MyType

{

public String StringMember { get; set; }

 

//隐式转换为String类型的定义

public static implicit operator String(MyType aString)

{

return aString.StringMember;

}

 

//String类型转换为MyType类型的定义

public static implicit operator MyType(String aString)

{

return new MyType { StringMember = aString };

}

}

var answer1 = GetSomeStrings().Cast<MyType>();

try

{

foreach (var v in answer1)

Console.WriteLine(v);

}

catch (InvalidCastException)

{

Console.WriteLine("Cast Failed!");

}

 

上面的代码会抛出InvalidCastException异常,因为Cast<T>方法并不认识MyType的那些隐式类型转换转换方法,所以自然抛出异常。

 

var answer3 = from v in GetSomeStrings()

select (MyType)v;

foreach (var v in answer3)

Console.WriteLine(v);

 

上面的代码可以成功,因为其使用了Reference conversion类型转换。

 

有两种转换可以使隐式或显示类型转换起作用:

Reference conversion :当 is 操作成功时

Boxing conversion:装箱操作,将值类型转换为引用类型

 

你也可以这样写:

var answer4 = GetSomeStrings().Select(n => new MyType { StringMember = n });

var answer5 = from v in GetSomeStrings()

       select new MyType { StringMember = v };

 

这样的话你可能需要为每一个集合枚举的遍历进行类型转换,其实大可不必。我们可以写一个通用的Convert<T>扩展方法,其实现逻辑如下:

public static IEnumerable<TResult> Convert<TResult>( this System.Collections.IEnumerable sequence)

{

foreach (object item in sequence)

{

dynamic coercion = (dynamic)item;

yield return (TResult)coercion;

}

}

在使用的时候我们可以这样:

var convertedSequence = GetSomeStrings().Convert<MyType>();