为什么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; }
这不会调用任何用户定义的转换 – 甚至是从(例如) int
到long
转换。 它只会执行参考转换和装箱/拆箱转换。 这只是仿制药工作方式的一部分。
Enumerable.Cast
是一种.Net框架方法,其行为在所有调用它的.Net语言中都有意义。
另见Ander Hejlsberg 对此讨论的回复。
编译器是否加重了我的显式演员?
你所谓的“隐式转换运算符 ”实际上是一个“ 隐式转换运算符 ”。 这是一个常见的错误。
C#允许您使用强制语法指定转换。 发生这种情况时,您使用的是另一个实例(转换),而不是更改对同一实例(转换)的引用。