2017-02-19 99 views
0

美好的一天,所有。C#將泛型,繼承類型和接口轉換爲具有相同接口的基類型

我可以問你邏輯爲什麼這是不可能的嗎? 我正在學習接口& generic,我認爲這是可能的,因爲Group實現了iPoppable & iPushable。但編譯器抱怨說,將iPoppable轉換爲Group是不可能的。我想知道爲什麼這是不可能的邏輯。

interface iPoppable<out T>{T Pop();} 
interface iPushable<in T>{void Push(T ag_t);} 

class Program 
{ 
    static void Main() 
    { 
     iPoppable<Lion> lions = new Group<Lion>(); 
     iPoppable<Animal> animals = lions; //Possible 
     Group<Lion> lions2 = lions; //Not possible 
    } 
} 

class Animal{} 
class Lion:Animal{} 

class Group<T>:iPoppable<T>, iPushable<T> 
{ 
    public void Push(T ag_t){} 
    public T Pop(){return something;} 
} 
+0

對於初學者,您的「Group」分類中的簽名不正確。 Pop應該返回'T'類型的對象,而不是void。你還需要研究協變*和*反變換。 – lintmouse

+0

謝謝。剛剛糾正。是的。我只是讀了他們兩個。 –

回答

3

好吧,一步一步來。

iPoppable<Lion> lions = new Group<Lion>(); 

作品,因爲Group實現iPoppable和泛型參數T是一樣的。

iPoppable<Animal> animals = lions; 

作品,因爲他們兩人都是iPoppableLionAnimal派生。更正式地說,這是協方差的一個例子。

將實例化爲更多派生類型參數的對象分配給實例化派生類型參數較少的對象。分配兼容性被保留。

來自Microsoft Docs

Group<Lion> lions2 = lions; 

不起作用,因爲您將接口類型分配給類類型。 iPoppable只是說lionsLion Pop();方法,沒有更多!通過說Group<Lion> lions2 = lions;你聲稱,lions2是一個全功能的Group對象,它將有所有方法和屬性Group類。這是不一定是真的,這就是爲什麼編譯器抱怨。

您可以說

Group<Lion> lions2 = (Group<Lion>)lions; 

因爲你知道一個事實,即特別lions,雖然類型爲iPoppable其實Group幫助編譯器。

爲了說明編譯器害怕什麼,請參閱以下代碼片段。

interface iPoppable<out T> 
{ 
    T Pop(); 
} 
interface iPushable<in T> 
{ 
    void Push(T ag_t); 
} 

class Program 
{ 
    static void Main() 
    { 
     // Here, we know the truth, so we cast 
     iPoppable<bool> group = new Group<bool>(); 
     Group<bool> group2 = (Group<bool>)group; // Possible 

     // What about here? We also convert iPoppable to Group... 
     iPoppable<bool> notGroup = new NotGroup<bool>(); 
     Group<bool> notGroup2 = (Group<bool>)notGroup; // Bad... Compiler was right... 

     notGroup2.HelloGroup = true; // HA! Runtime exception. 
     // That's what compiler was worrying about. 

     // System.InvalidCastException: Unable to cast object of 
     // type 'NotGroup`1[System.Boolean]' to type 'Group`1[System.Boolean] 
    } 
} 

class Group<T> : iPoppable<T>, iPushable<T> 
{ 
    public void Push(T ag_t) { } 
    public T Pop() { return default(T); } 

    public bool HelloGroup { get; set; } 
} 

class NotGroup<T> : iPoppable<T>, iPushable<T> 
{ 
    public void Push(T ag_t) { } 
    public T Pop() { return default(T); } 

    public bool HelloNotGroup { get; set; } 
} 
+0

美好的一天,Dmytro。感謝您的親切解釋。的確,不是語法,但我想知道邏輯!因爲發表評論爲時已晚,我首先表示感謝,然後纔開始查看您的摘錄。如果允許,我想在此主題中詢問更多問題。祝你今天愉快! –

+0

我檢查了你的代碼片段,得出的結論是隱式轉換不允許,即使實現的接口和類型相同,因爲在C#規範中允許顯式轉換。一旦具有相同接口的不同類型轉換爲其他類型,這可能會導致運行時錯誤。那麼,是否希望不要在這個動物園做明確的演員? –

+0

@騎自行車狗 - 我很高興我的答案幫助!至於你的問題,讓我們定義正確的條款。隱式轉換不是轉換,它是一種類型安全的類型轉換,它總是成功並且不會丟失任何數據。示例將派生類型轉換爲基類型。顯式強制轉換(帶有括號的語法)可能會失敗(+數據丟失)。如果右側不是正確的類型,它可能會拋出異常。總體思路是儘可能避免顯式轉換。你總是可以用反射來檢查類型或者捕捉異常,但這是不好的做法。 –