C#泛型:重写方法中继承约束的显式重述可能会破坏多态性

本文关键字:多态性 重写 泛型 方法 约束 继承 | 更新日期: 2023-09-27 17:58:29

Mark Michaelis在他的书(C#4.0 Essentials)中写道:

class EntityBase<T> where T : IComparable<T>
{
    public virtual void Method<T>(T t)
      where T : IComparable<T>
    {
        // ...
    }
}
class Entity<T> : EntityBase<T> where T : IComparable<T>
{
    public override void Method<T>(T t)
        // Error: Constraints may not be
        // repeated on overriding members
    where T : IComparable<T>
    {
        // ...
    }
}

但是,压倒一切的成员需要符合中定义的"接口"基类方法。附加的约束可以打破多态性,因此它们是不允许的,并且类型替代上的参数约束方法是隐含的。

有人能向我解释一下这对break polymorphism意味着什么吗?在这个例子中,多态性是如何打破的?

C#泛型:重写方法中继承约束的显式重述可能会破坏多态性

他的例子之所以令人困惑,部分原因是(不正确,IMO)在泛型类型中对泛型方法重复使用了T。两个T不一样!所以让我们使用一个非泛型类型:

class EntityBase
{
    public virtual void Method<T>(T t)
      where T : IComparable<T>
    {
        // ...
    }
}
class Entity : EntityBase
{
    public override void Method<T>(T t)
        // Error: Constraints may not be
        // repeated on overriding members
    where T : IComparable<T>, ISomethingElse
    {
        // ...
    }
}

在这里,我添加了ISomethingElse,很明显,第二个方法可以尝试使用第二个T的功能,但是,调用方可能是:

EntityBase foo = GetEntity(); // is actually an Entity (sub-type) instance
foo.Method<SomeType>();
...
EntityBase GetEntity() { return new Entity(); }

基本实现不强制执行ISomethingElse,因此编译器不会抱怨它没有实现。那么被重写的方法是做什么的呢?因此它不可能存在。

然而!如果您改为在类型级别执行此操作,则确实有效,因为对于存在的具体对象,我们知道强制执行了约束:

class EntityBase<T> where T : IComparable<T>
{
    public virtual void Method(T t)
    {
        // ...
    }
}
class Entity<T> : EntityBase<T>
   where T : IComparable<T>, ISomethingElse
{
    public override void Method(T t)
    {
        // ... can use ISomethingElse features
    }
}

还有一个简短的提醒——如果你有一个带有<T>的泛型类型,不要在泛型方法中也使用<T>;更具体的东西,比如TValue等等…

如果您能够向重写的方法添加额外的约束,它将破坏多态性。

特别是,使用不满足新约束的参数调用基方法的代码会中断。

例如:

class Base {
    public virtual void M<T>() where T : Control { ... }
}
class Derived: Base {
    public override void M<T>() where T : Button { ... }
}

Base b = new Derived();
b.M<TextBox>();    //That's not a Button!