簡體   English   中英

泛型和類繼承的混淆

[英]Generics and Class Inheritance confusion

我有以下代碼塊作為我遇到的問題的簡化示例。 但是我收到一個錯誤消息,聲稱我無法將一種類型轉換為另一種類型。 我用LINQPad進行了測試。

void Main()
{
    LivingThing<Appendage> mysteryAnimal = new Cat();
}

public class Appendage { }
public class Paw : Appendage { }

public class LivingThing<TExtremity> where TExtremity : Appendage { }
public class Animal<TExtremity> : LivingThing<TExtremity> where TExtremity : Appendage { }
public class Cat : Animal<Paw> { }

為什么我不能投CatLivingThing<Appendage>當我知道貓的定義是使用的子類LivingThingAppendage

通過向其中一個類中添加一種方法,不難理解為什么您嘗試執行的操作無法進行一些修改:

public class LivingThing<TExtremity> where TExtremity : Appendage {
    private TExtremity extremity;
    public void SetExtremity(TExtremity e) {
        extremity = e;
    }
}

現在,讓我們想象一下C#使您可以進行分配。 然后,它應該讓您執行以下操作:

public class Hand : Appendage { }
...
// Let's pretend this works
LivingThing<Appendage> cat = new Cat();
// Now that C# let us do the assignment above, it must allow this too,
// because Cat is a LivingThing and Hand is an Appendage:
cat.SetExtremity(new Hand());

糟糕,我們有一只手扶着的貓! C#不應該讓我們這樣做。

但是,如果LivingThing具有返回 TExtremity方法,則可以做您想做的事情。 C#提供了定義繼承層次結構的方法,使您可以按照自己的嘗試靈活地分配。 這是修改后的代碼,可以正常工作:

void Main()
{
    ILivingThing<Appendage> mysteryAnimal = new Cat();
}

public class Appendage { }
public class Paw : Appendage { }

public interface ILivingThing<out TExtremity> where TExtremity : Appendage { }
// You have a choice of keeping Animal a class. If you do, the assignment
// Animal<Appendage> mysteryAnimal = new Cat()
// would be prohibited.
public interface IAnimal<TExtremity> : ILivingThing<out TExtremity> where TExtremity : Appendage { }
public class Cat : Animal<Paw> { }

有一個陷阱: ILivingThing<TExtremity>IAnimal<TExtremity>都不允許具有TExtremity類型的可設置屬性或以TExtremity作為參數的方法。

您嘗試做的就是“協方差”; 將具有較多派生的泛型參數的泛型類的實例分配給具有較少派生的泛型參數的類的變量。

在C#中,類不支持此功能。 對於接口,必須明確指定。 將編譯以下內容:

void Main()
    {
        ILivingThing<Appendage> mysteryAnimal = new Cat();
    }

    public class Appendage { }
    public class Paw : Appendage { }

    public interface ILivingThing<out TExtremity> where TExtremity : Appendage { }
    public class Animal<TExtremity> : ILivingThing<TExtremity> where TExtremity : Appendage { }
    public class Cat : Animal<Paw> { }

這對於您的實際代碼是否可以接受,取決於LivingThing的定義方式。 如果它是“標記類”(沒有成員;僅作為將其子代標識為LivingThings的派生點而存在),或者是沒有非抽象成員的抽象類,則它應該像一種魅力。 如果此類中有成員代碼,則需要從該類中提取協變接口。

暫無
暫無

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

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