[英]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
具有通用參數,您無法刪除該參數。
我認為您已接近解決方案,但我認為您有一點倒掛的想法。 而不是讓非泛型的Fruit
從GenericFruit<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>
就是行不通,因為您通過說T
為Fruit<T>
來創建無限循環。 (開始更換T
的Fruit<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.