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

Ben*_*son 18 c# linq extension-methods casting

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

DTOType MyDTO = (LinqToSQLType)MyLinq2SQLObj;
Run Code Online (Sandbox Code Playgroud)

这很好用.

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

List<DTO.Name> Names = dbContact.tNames.Cast<DTO.Name>()
                                               .ToList();
Run Code Online (Sandbox Code Playgroud)

但下面的工作正常:

DAL.tName MyDalName = new DAL.tName();
DTO.Name MyDTOName = (DTO.Name)MyDalName;
Run Code Online (Sandbox Code Playgroud)

以下也行得正常

List<DTO.Name> Names = dbContact.tNames.Select(name => (DTO.Name)name)
                                               .ToList();
Run Code Online (Sandbox Code Playgroud)

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

LBu*_*kin 25

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
Run Code Online (Sandbox Code Playgroud)

不要紧,一UDC是否存在从SomeTypeOtherType-它无法通过类型的参考应用object.尝试运行上面的代码会在运行时失败,报告类似于:

System.InvalidCastException: 
    Unable to cast object of type 'SomeType' to type 'OtherType'
Run Code Online (Sandbox Code Playgroud)

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

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

  • @Ben:想象一下,你正在构建一个像CLR一样的运行时.你真的想在运行时嵌入用于绑定转换的C#编程语言的规则吗?如果VB/F#/ JScript/Perl/Ruby/C/C++/J#/ Python/...规则不同怎么办?为什么C#规则应该在运行时得到特殊处理?因此,您在运行时获得的规则是最简单的"最小公分母"; 只是一种类型测试.如果您想要编译时行为,可以在C#4中使用"dynamic"来在运行时获取它,或者编写代码以便在编译时完成转换的分辨率. (2认同)