簡體   English   中英

為什么C#編譯器允許在IEnumerable <T>和TAlmostAnything之間進行顯式轉換?

[英]Why does the C# compiler allow an explicit cast between IEnumerable<T> and TAlmostAnything?

以下代碼為您提供編譯器錯誤,正如您所期望的那樣:

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

Banana justOneBanana = (Banana)aBunchOfBananas;

但是,使用IEnumerable<Banana> ,只會出現運行時錯誤。

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

Banana justOneBanana = (Banana)aBunchOfBananas;

為什么C#編譯器允許這樣做?

我想這是因為IEnumerable<T>是一個接口,其中一些實現可以Banana進行顯式轉換 - 無論多么愚蠢。

另一方面,編譯器知道List<T>不能顯式地轉換為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...
}

然后你可以這樣做:

IEnumerable<Banana> aBunchOfBananas = new SingleItemList<Banana>();
Banana justOneBanana = (Banana)aBunchOfBananas;

因為它與編寫以下內容相同,編譯器非常滿意:

Banana justOneBanana = aBunchOfBananas.SingleOrDefault();

當你說Y y = (Y)x; 這個演員對編譯器說:“相信我,無論x是什么,在運行時它都可以轉換為Y ,所以,就這樣做,好嗎?”

但是當你說的時候

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

編譯器可以查看每個具體類( BananaList<Banana> )的定義,並看到沒有定義static explicit operator Banana(List<Banana> bananas) (請記住,必須在任一個中定義顯式轉換被鑄造的類型或鑄造的類型,這是來自規范,第17.9.4節)。 它在編譯時知道你所說的不可能是真的。 所以你大吼大叫停止說謊。

但是當你說的時候

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

好吧,現在編譯器不知道。 很有可能的情況是,無論aBunchOfBananas恰好在運行時,其具體類型X可以定義static explicit operator Banana(X bananas) 所以編譯器信任你,就像你問的那樣。

這可能是因為編譯器知道 Banana沒有擴展List<T> ,但是實現IEnumerable<T>某個對象也可能會擴展Banana並使其成為有效的強制轉換。

根據語言規范(6.2.4)“顯式引用轉換是:從任何類型S到任何接口類型T,如果S未密封且提供S未實現T ...顯式引用轉換是那些引用類型之間的轉換需要運行時檢查以確保它們是正確的......“

因此編譯器在編譯期間不檢查接口實現。 它在運行時執行CLR。 它檢查元數據,試圖在類中或在其父類中查找實現。 我不知道為什么它會像這樣。 可能需要很多時間。 所以這段代碼正確編譯:

public interface IInterface
{}

public class Banana
{
}

class Program
{
    static void Main( string[] args )
    {
        Banana banana = new Banana();

        IInterface b = (IInterface)banana;
    }
}

另一方面,如果我們嘗試將banana轉換為類,編譯器會檢查其元數據並拋出錯誤:

 FileStream fs = (FileStream)banana;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM