为什么C#编译器允许在IEnumerable <T>和TAlmostAnything之间进行显式转换?

Dan*_*nny 59 .net c# generics compiler-errors

以下代码为您提供编译器错误,正如您所期望的那样:

List<Banana> aBunchOfBananas = new List<Banana>();

Banana justOneBanana = (Banana)aBunchOfBananas;
Run Code Online (Sandbox Code Playgroud)

但是,在使用时IEnumerable<Banana>,您只会收到运行时错误.

IEnumerable<Banana> aBunchOfBananas = new List<Banana>();

Banana justOneBanana = (Banana)aBunchOfBananas;
Run Code Online (Sandbox Code Playgroud)

为什么C#编译器允许这样做?

Yuc*_*uck 48

我想这是因为它IEnumerable<T>是一个接口,某些实现可以有一个显式的强制转换Banana- 无论多么愚蠢.

另一方面,编译器知道List<T>无法显式地转换为a Banana.

顺便说一下,很好的例子选择!

添加一个例子来澄清.也许我们有一些"可枚举的"应该总是包含最多一个Banana:

public class SingleItemList<T>:Banana, IEnumerable<T> where T:Banana {
    public static explicit operator T(SingleItemList<T> enumerable) {
        return enumerable.SingleOrDefault();
    }

    // Others omitted...
}
Run Code Online (Sandbox Code Playgroud)

然后你可以这样做:

IEnumerable<Banana> aBunchOfBananas = new SingleItemList<Banana>();
Banana justOneBanana = (Banana)aBunchOfBananas;
Run Code Online (Sandbox Code Playgroud)

因为它与编写以下内容相同,编译器非常满意:

Banana justOneBanana = aBunchOfBananas.SingleOrDefault();
Run Code Online (Sandbox Code Playgroud)

  • 你不能这样做 - 它找不到运营商.一个例子是`class SingleBanana:Banana,IEnumerable <Banana>`.这就是为什么它只适用于接口 - 因为如果两个类型都是类,那么在编译时就可以确定这是不可能的. (4认同)

jas*_*son 29

当你说Y y = (Y)x;这个演员对编译器说:"相信我,无论如何x,在运行时它可以被转换为a Y,所以,就这样做,好吗?"

但是当你说的时候

List<Banana> aBunchOfBananas = new List<Banana>();
Banana justOneBanana = (Banana)aBunchOfBananas;
Run Code Online (Sandbox Code Playgroud)

编译器可以查看每个具体类(BananaList<Banana>)的定义,并看到没有static explicit operator Banana(List<Banana> bananas)定义(请记住,必须在要转换的类型或要转换的类型中定义显式转换,这是来自规范,第17.9.4节).它在编译时知道你所说的不可能是真的.所以你大吼大叫停止说谎.

但是当你说的时候

IEnumerable<Banana> aBunchOfBananas = new List<Banana>();
Banana justOneBanana = (Banana)aBunchOfBananas;
Run Code Online (Sandbox Code Playgroud)

好吧,现在编译器不知道.很有可能的情况是,无论aBunchOfBananas在运行时发生什么,它的具体类型X都可以定义static explicit operator Banana(X bananas).所以编译器信任你,就像你问的那样.


eou*_*3hf 16

这可能是因为编译器知道Banana不扩展List<T>,但有一种可能性,即一些对象,它实现IEnumerable<T>也可延伸Banana并作出有效的演员.