我试图了解约束(在类或泛型方法上)如何影响方法本身。以这段代码为例:
class Base<T> where T:class, IComparable<T>
{
public virtual void Method(T obj) { }
}
class Derived<T> : Base<T> where T:class, IComparable<T>, IEnumerable<T>
{
public override void Method(T obj) { }
}
此代码编译良好,编译器/运行时能够解析对非泛型方法“Method”的多态调用,该方法采用泛型类型的参数。在基类和派生类中,对类型参数的约束是不同的。
我还指定了一个类约束来排除可能会导致问题的值类型,因为为每个值类型实例化生成了一个不同的类,而只有一个这样的类为引用类型实例化。
另一方面,以下代码无法编译。
class Base
{
public virtual void Method<T>() where T : class, IComparable<T> { }
}
class Derived : Base
{
public override void Method<T>() where T : class, IComparable<T>, IEnumerable<T> { }
}
C# 的语言规范说对泛型方法的约束按原样转移到覆盖方法,并且指定任何约束都是非法的。我在 Google 上进行了一些搜索,发现这是不允许的,因为与支持多态调用相关的复杂性(关于维护方法表等)。但我仍然不明白为什么它在上面的案例 1 中起作用,除了它是泛型的类之外,它与此类似。编译器/运行时如何在案例 1 中做到这一点,而案例 2 被标记为编译器错误?
最佳答案
让我们考虑一下这个问题“为什么在虚拟覆盖中向泛型方法添加约束是非法的?”因为这真的很简单。
class Foo : IComparable<Foo> { ... }
...
Base b = new Derived();
b.Method<Foo>();
首先,这是否违法?是的。调用
b.Method<Foo>
实际调用的是 Derived.Method<Foo>
,但是 Foo
不符合约束条件。所以这一定是非法的。应该在哪一行代码上报告错误?
Foo
的声明是合法的。 Derived
到 Base
的转换是合法的。从编译器的角度来看,对 b.Method<Foo>
的调用是合法的; b
的类型为 Base
并且 Foo
满足 Base.Method
的约束。因此不能在任何这些行上报告错误。报告错误的唯一地方是 Base.Method
中包含导致问题的 where
子句的行。因此,这种 where
子句必须是非法的,以防止任何人编写上述其他合法的程序片段。现在你的第一个案例是什么,类是泛型的?那么,在这种情况下,您将如何获得
Base<Foo>
?当然不是来自 Derived<Foo>
的实例,因为您甚至无法首先创建该类型!等效的问题程序是:Base<Foo> b = new Derived<Foo>();
b.Method();
现在应该在哪里报告错误?很明显,它可以在创建
Derived<Foo>
的行上报告!所以没有必要使额外的 where
子句非法。关于c# - 重写泛型方法的约束,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38565483/