簡體   English   中英

將通用類型引用存儲在C#中

[英]Store generic type reference in C#

我將某些Java代碼移植到C#,並且在復制此行為時遇到了麻煩:

***** JAVA代碼*****

public abstract class Fruit<T extends Fruit>{
   //Fruit implementation
}

這很棒,因為我只想要擴展Fruit的通用類型。 然后,我可以為所有具體水果對象存儲一個引用,如下所示:

Banana banana = new Banana(); //This class extends Fruit
Strawberry strawberry = new Strawberry (); //This class extends Fruit

Fruit fruit;
fruit = banana;
//or
fruit = strawberry;

這樣很好。 現在我正在C#中嘗試相同的操作,並且Fruit類的聲明如下:

***** C#代碼*****

abstract public class Fruit<T> where T : Fruit<T> {
  //Fruit implementation
}

但是在C#中,我不能存儲這樣的引用:

Fruit fruit; //This gives a compilation error!

我無法將香蕉和草莓存儲在同一參考中,我只能這樣做:

Fruit<Banana> fruit;
fruit = banana;
//or
Fruit<Strawberry> fruit;
fruit = strawberry;

我認為我可以通過添加這樣的繼承級別來解決它:

abstract public class GenericFruit<T> where T : GenericFruit<T> {}

然后創建等效的Fruit類

abstract public class Fruit : GenericFruit<Fruit>{}

現在像這樣從水果中擴展香蕉和草莓:

public class Banana : Fruit {}
public class Strawberry : Fruit {}

然后存儲一個Fruit引用:

Fruit fruit;
fruit = new Banana();
fruit = new Strawberry();

但這聽起來有點像作弊:(有什么想法嗎?我做錯了嗎?

您遇到的問題是您試圖“忘記”(或擦除)您創建的某些類型信息。 讓我們通過在基類中添加一個方法來使示例更加具體:

public abstract class Fruit<T> where T : Fruit<T>
{
    public abstract T GetSeedless();
}

好的,現在讓我們更仔細地看看您要做什么。 假設您可以完全按照自己的意願去做,並且擁有一個水果籃:

Fruit fruit = new Apple();
var seedlessFruit = fruit.GetSeedless();

好吧,是什么類型seedlessFruit 您可能傾向於說它是Fruit ,那是合理的,但是C#不允許這樣做。 C#不允許您擦除類的通用參數。 當您聲明Fruit<T>您譴責所有Fruit具有通用參數,您無法刪除該參數。

我認為您已接近解決方案,但我認為您有一點倒掛的想法。 而不是讓非泛型的FruitGenericFruit<Fruit>繼承,您應該翻轉它並使泛型版本從非泛型的Fruit繼承。

我還有一個建議,那就是將非泛型的Fruit變成一個接口而不是一個抽象類。 我將說明原因(最終是因為C#在覆蓋方法時不允許返回類型協方差;可以肯定的是,這很麻煩)。

public interface IFruit
{
    IFruit GetSeedless();
}

public abstract class Fruit<T> : IFruit where T : Fruit<T>
{
    public abstract T GetSeedless();

    IFruit IFruit.GetSeedless()
    {
        return GetSeedless();
    }
}

我在這里所做的是通過在Fruit類中顯式實現IFruit接口來創建假返回類型協方差。 現在,您可以將不同種類的水果存儲在同一引用中,並且仍然使用GetSeedless方法:

IFruit fruit = new Apple();
var seedlessFruit = fruit.GetSeedless();

這也使您可以選擇要擦除通用信息時應使用的方法和屬性。 這些方法中的每一個都可以在基類中顯式實現,並用通用版本“替換”。 這樣,如果您確實具有通用類型信息,則可以使用更特定的類型。

首先,這是:

abstract public class Fruit<T> where T : Fruit<T>

就是行不通,因為您通過說TFruit<T>來創建無限循環。 (開始更換TFruit<T>Fruit<T>你會看到這是不可能結束)。

編輯:正如凱爾所說,這可行。

解決方案可能是:

abstract public class Fruit
{
    // Generic implementation
}

abstract public class Fruit<T> : Fruit
    where T : Fruit // edit: or Fruit<T>
{
    // Overriding generic implementation
}

您可能會:

public class Banana : Fruit<YourType> // edit: or Fruit<Banana>
{
    // Specific implementation
}

最后,這應該很好地工作:

Fruit fruit;
fruit = new Banana();
fruit = new Strawberry();

暫無
暫無

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

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