LINQ .Cast()扩展方法失败但(类型)对象有效

要在一些LINQ to SQL对象和DTO之间进行转换,我们在DTO上创建了显式的转换运算符。 这样我们就可以做到以下几点:

DTOType MyDTO = (LinqToSQLType)MyLinq2SQLObj; 

这很好用。

但是,当您尝试使用LINQ .Cast()扩展方法进行强制转换时,它会抛出一个无效的强制转换exception,表示无法将类型Linq2SQLType转换为类型为DTOType。 即以下不起作用

 List Names = dbContact.tNames.Cast() .ToList(); 

但以下工作正常:

 DAL.tName MyDalName = new DAL.tName(); DTO.Name MyDTOName = (DTO.Name)MyDalName; 

以下也行得正常

 List Names = dbContact.tNames.Select(name => (DTO.Name)name) .ToList(); 

为什么.Cast()扩展方法会抛出无效的强制转换exception? 我过去曾多次使用.Cast()扩展方法,当你将类似基类型的类型转换为派生类型时,它可以正常工作,但是当对象有一个显式的强制转换操作符时,它就会失败。

Cast<>扩展方法不应用用户定义的转换。 它只能转换为接口或所提供类型的类层次结构。

用户定义的转换在编译时根据表达式中涉及的静态类型进行标识。 它们不能用作运行时转换,因此以下内容是非法的:

 public class SomeType { public static implicit operator OtherType(SomeType s) { return new OtherType(); } } public class OtherType { } object x = new SomeType(); OtherType y = (OtherType)x; // will fail at runtime 

UDC是否存在从SomeTypeOtherType – 它不能通过类型object的引用来应用。 尝试运行上面的代码会在运行时失败,报告如下:

 System.InvalidCastException: Unable to cast object of type 'SomeType' to type 'OtherType' 

Cast<>()只能执行保留转换的表示…这就是为什么你不能用它来应用用户定义的转换。

Eric Lippert有一篇关于C#中演员操作符行为的精彩文章 – 总是值得一读。

如果您对Linq程序集进行反编译,则会得到类似以下内容的代码。 之前的答案是正确的,最终演员阵容从“对象”到目标类型,对于自定义类型总是会失败。

 private static IEnumerable CastIterator( IEnumerable source ) { foreach(object current in source) { yield return (TResult)( (object)current ); } yield break; } public static IEnumerable DCast( this IEnumerable source ) { IEnumerable enumerable = source as IEnumerable; if(enumerable != null) { return enumerable; } if(source == null) { throw new ArgumentNullException( "source" ); } return CastIterator( source ); } 

TFish

对于那些遇到这个问题寻找解决方法的人……

 Dim res = arrayOfStrings.Select(Function(__) CType( __, YourType )) 

不确定C#的确切语义,但我确信这很容易。