[英]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.