18

在决定投票为重复之前,请阅读到最后......

我有一种将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<>,并没有什么神奇之处:如果参数确实是 a IEnumerable<B>,则有一些特殊情况,然后:

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

那么为什么我的显式演员表起作用,但里面的演员表不起作用.Cast<>

编译器会加糖我的显式转换吗?

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

4

3 回答 3

16

那么为什么我的显式演员表起作用,而 .Cast<> 里面的演员表却不起作用?

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

泛型类型并非如此。请注意,这通常不是特定于CastLINQ 或 LINQ - 如果您尝试一个简单的Convert方法,您会看到同样的事情:

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

不会调用任何用户定义的转换 - 甚至不会调用从(比如说)intlong. 它只会执行参考转换和装箱/拆箱转换。这只是泛型工作方式的一部分。

于 2013-01-25T14:14:59.127 回答
11

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

在第一个示例中:

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

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

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

不了解操作者信息;这是通过实现unbox.any的(这与castclassifT是 ref 类型相同)。

还有第三种选择:如果您通过 via dynamic,运行时实现会尝试模仿编译器规则,因此这找到运算符 ... 但不是 C#-to-IL 编译步骤的一部分:

dynamic b = a; // note that `dynamic` here is *almost* the same as `object`
B b2 = b;
于 2013-01-25T14:19:22.103 回答
3

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

另请参阅 Ander Hejlsberg对此讨论的回复。


编译器会加糖我的显式转换吗?

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

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

于 2013-01-25T14:54:31.880 回答