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

时间:2013-01-25 14:12:43

标签: c# linq casting implicit-conversion coercion

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

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

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

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

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

......那么Linq的.Cast<>怎么没有?

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

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

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

那么为什么我的显式投射工作,而不是.Cast<>内部的工作?

编译器是否会对我的显式转换加油?

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

3 个答案:

答案 0 :(得分:13)

  

那么为什么我的显式演员工作,以及里面的那个.Cast&lt;&gt;不?

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

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

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

这将调用任何用户定义的转化 - 甚至从({)int转换为long。它执行引用转换和装箱/拆箱转换。这只是仿制药工作方式的一部分。

答案 1 :(得分:8)

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

在第一个例子中:

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

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

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

对操作员无知识;这是通过unbox.any实现的(如果castclass是ref-type,则与T相同。)

还有第三种选择:如果你通过dynamic,运行时实现会尝试模仿编译器规则,所以找到运算符...但不是作为C#-to-IL编译步骤:

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

答案 2 :(得分:2)

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

另见Ander Hejlsberg对this discussion的回复。


  

编译器是否会对我的显式转换加油?

你称之为“隐式演员”的实际上是“implicit conversion operator”。这是一个常见的错误。

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