我试图了解约束(在类或泛型方法上)如何影响方法本身。以这段代码为例:

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 的声明是合法的。 DerivedBase 的转换是合法的。从编译器的角度来看,对 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/

10-08 20:37