【发布时间】:2011-12-22 15:56:05
【问题描述】:
物品类别
public class Item
{
public bool Check(int value) { ... }
}
具有泛型类型约束的基本抽象类
public abstract class ClassBase<TItem>
where TItem : Item
{
protected IList<TItem> items;
public ClassBase(IEnumerable<TItem> items)
{
this.items = items.ToList();
}
public abstract bool CheckAll(int value);
}
没有约束的继承类
public class MyClass<TItem> : ClassBase<TItem>
{
public override bool CheckAll(int value)
{
bool result = true;
foreach(TItem item in this.items)
{
if (!item.Check(value)) // this doesn't work
{
result = false;
break;
}
}
return result;
}
}
我想知道为什么泛型类型约束不可继承?因为如果我的继承类继承自基类并传递其对基类具有约束的泛型类型,则它自动意味着继承类中的泛型类型应该具有相同的约束,而无需显式定义它。不应该吗?
是我做错了什么,理解错了还是泛型类型约束真的不可继承?如果后者是真的,这到底是为什么?
一点补充说明
为什么我认为在一个类上定义的泛型类型约束应该被继承或在子类上强制执行?让我给你一些额外的代码,让它不那么明显。
假设我们拥有上述所有三个类。然后我们也有这个类:
public class DanteItem
{
public string ConvertHellLevel(int value) { ... }
}
我们可以看到这个类不是从Item 继承的,所以它不能像ClassBase<DanteItem> 那样用作具体类(忘记ClassBase 现在是抽象的事实。它也可以是一个普通班)。由于MyClass 没有为其泛型类型定义任何约束,因此拥有MyClass<DanteItem> 似乎完全有效...
但是。这就是为什么我认为泛型类型约束应该像成员泛型类型约束一样在继承类上继承/强制执行,因为如果我们查看MyClass 的定义,它会说:
MyClass<T> : ClassBase<T>
当T 是DanteItem 时,我们可以看到它自动不能与MyClass 一起使用,因为它是从ClassBase<T> 继承的,而DanteItem 不满足其泛型类型约束。我可以说MyClass 上的**泛型类型取决于ClassBase 泛型类型约束,因为否则MyClass 可以用任何类型实例化。但我们知道不可能。
如果我将MyClass 定义为:
public class MyClass<T> : ClassBase<Item>
在这种情况下,T 与基类的泛型类型没有任何关系,因此它独立于它。
这是一个有点长的解释/推理。我可以简单地总结为:
如果我们不对
MyClass提供泛型类型约束,则暗示我们可以用任何具体类型 实例化MyClass。但我们知道这是不可能的,因为MyClass是从ClassBase继承而来的,并且它具有泛型类型约束。
我希望现在这更有意义。
【问题讨论】:
-
我正在查看语言规范,我看到“由于没有继承类型参数,因此也永远不会继承约束”(第 4.4.4 节)。这引出了一个问题“为什么不继承类型参数?”这可能会导致对开放类型和封闭类型以及类似事物的更深入讨论,也在规范中。从实际的角度来看,必须重述约束可能对您离基本类型越远越好,尤其是在闭源程序集中时。
-
@AnthonyPegram:类型参数不是继承的(1)因为它们不是成员,(2)因为这没有任何意义。您从 type 继承。未构造的泛型类型不是类型,因此您不能从它继承。要从泛型类型继承,您必须构造类型,这意味着用某些东西代替类型参数。类型参数不是您从基类获得的事物!它是基类中的一个hole,您必须先填充它才能继承from。
-
@EricLippert 我相信让 OP 跳闸的是,虽然约束不是 de jure 继承的(所以依赖于约束编译的代码,嗯,赢了't) 基类型的约束仍然与派生类型的用户非常相关,因为派生类型的类型参数仍必须满足基类型的约束。
-
在使用泛型类进行继承时,有很多可能的场景/组合,尤其是当一个类具有多个泛型参数时。一个彻底的答案可能会提供一堆示例,其中这种行为的隐含性质可能会导致混淆。我认为一个非常适用的quote from Eric Lippert 是:C# 的设计原则之一是“如果你说错了,我们会告诉你,而不是试图猜测你的意思”
标签: c# inheritance generic-constraints