为什么Linq Cast 助手不能与隐式强制转换操作符一起使用?

请在决定投票前重复阅读…

我有一个类型,它实现了另一种类型的implicit cast运算符:

 class A { private B b; public static implicit operator B(A a) { return ab; } } class B { } 

现在,隐式和显式转换工作正常:

 B b = a; B b2 = (B)a; 

……那么Linq的.Cast怎么没有?

 A[] aa = new A[]{...}; var bb = aa.Cast(); //throws InvalidCastException 

查看.Cast的源代码,没有太大的魔力:如果参数确实是IEnumerable ,则会出现一些特殊情况,然后:

 foreach (object obj in source) yield return (T)obj; // ^^ this looks quite similar to the above B b2 = (B)a; 

那么为什么我的显式转换工作,而不是内部的.Cast

编译器是否加重了我的显式演员?

PS。 我看到了这个问题,但我认为它的答案并没有真正解释发生了什么。

简短的回答很简单: Cast方法不支持自定义转换运算符。

在第一个例子中:

 B b = a; B b2 = (B)a; 

编译器可以在静态分析期间看到这个B(A a)运算符; 编译器将此解释为对自定义运算符方法的静态call 。 在第二个例子中:

 foreach (object obj in source) yield return (T)obj; 

不了解运营商的; 这是通过unbox.any实现的(如果T是ref-type,则与castclass相同)。

还有第三种选择:如果你通过dynamic ,运行时实现试图模仿编译器规则,所以这找到运算符……但不是C#-to-IL编译步骤的一部分:

 dynamic b = a; // note that `dynamic` here is *almost* the same as `object` B b2 = b; 

那么为什么我的显式演员工作,以及里面的那个.Cast <>不行?

您的显式转换在编译时知道源和目标类型是什么。 编译器可以发现显式转换,并发出代码来调用它。

generics类型不是这种情况。 请注意,这通常不是特定于Cast或LINQ的 – 如果您尝试使用简单的Convert方法,则会看到相同的内容:

 public static TTarget Convert(TSource value) { return (TTarget) value; } 

不会调用任何用户定义的转换 – 甚至是从(例如) intlong转换。 它只会执行参考转换和装箱/拆箱转换。 这只是仿制药工作方式的一部分。

Enumerable.Cast是一种.Net框架方法,其行为在所有调用它的.Net语言中都有意义。

另见Ander Hejlsberg 对此讨论的回复。


编译器是否加重了我的显式演员?

你所谓的“隐式转换运算符 ”实际上是一个“ 隐式转换运算符 ”。 这是一个常见的错误。

C#允许您使用强制语法指定转换。 发生这种情况时,您使用的是另一个实例(转换),而不是更改对同一实例(转换)的引用。