从泛型抽象类派生类的c#方法重载问题

本文关键字:方法 重载 问题 泛型 抽象类 派生 | 更新日期: 2023-09-27 17:49:20

我正在处理一个项目,并且我有一个通用的抽象类型,它接受一个类型参数,该参数本身派生自抽象类型。如果你想知道我为什么要这样做,请看看这个问题。

我遇到了一个有趣的问题,即在抽象类中定义的派生类中重载方法。下面是一个代码示例:

public abstract class AbstractConverter<T, U>
    where U : AbstractConvertible
    where T : AbstractConverter<T, U>
{
    public abstract T Convert(U convertible);
}
public class DerivedConvertibleConverter : AbstractConverter<DerivedConvertibleConverter, DerivedConvertible>
{
    public DerivedConvertibleConverter(DerivedConvertible convertible)
    {
        Convert(convertible);
    }
    public override DerivedConvertibleConverter Convert(DerivedConvertible convertible)
    {
        //This will not be called
        System.Console.WriteLine("Called the most derived method");
        return this;
    }
    public DerivedConvertibleConverter Convert(Convertible convertible)
    {
        System.Console.WriteLine("Called the least derived method");
        return this;
    }
}
public abstract class AbstractConvertible {}
public class Convertible : AbstractConvertible {}
public class DerivedConvertible : Convertible {}
在上面的示例中,调用了在抽象父类中不存在的Convert的重载(派生程度较低)。我希望从父类中调用最派生的版本。

在尝试解决这个问题时,我遇到了一个有趣的解决方案:

public abstract class AbstractConverter<U>
    where U : AbstractConvertible
{
    public abstract AbstractConverter<U> Convert(U convertible);
}
public class DerivedConvertibleConverter : AbstractConverter<DerivedConvertible>
{
    public DerivedConvertibleConverter(DerivedConvertible convertible)
    {
        Convert(convertible);
    }
    public override DerivedConvertibleConverter Convert(DerivedConvertible convertible)
    {
        System.Console.WriteLine("Called the most derived method");
        return this;
    }
    public DerivedConvertibleConverter Convert(Convertible convertible)
    {
        System.Console.WriteLine("Called the least derived method");
        return this;
    }
}
public abstract class AbstractConvertible {}
public class Convertible : AbstractConvertible {}
public class DerivedConvertible : Convertible {}

当从基类中删除派生类型参数时,将调用Convert的最派生版本。我没有预料到这种差异,因为我没有预料到Convert抽象版本的接口发生了变化。然而,我一定是错了。有人能解释一下为什么会出现这种差异吗?非常感谢。

从泛型抽象类派生类的c#方法重载问题

在上面的示例中,调用了在抽象父类中不存在的Convert的重载(派生程度较低)。我希望来自父类的最派生的版本将被称为

很多人都有这样的期望。但是,您正在观察的行为是正确的,并且是经过设计的。

重载解析算法是这样的。首先,我们列出所有可能调用的可访问方法。覆盖虚方法的方法被认为是声明它们的类的方法,而不是覆盖它们的类的方法。然后我们过滤掉那些实参不能转换为形式形参类型的实参。然后,我们过滤掉任何类型上的所有方法,这些方法派生的少于任何具有适用方法的类型。如果剩下的方法不止一个,则判断哪个方法比另一个方法更好。

在您的情况下,有两种可能适用的方法。接受DerivedConvertible的方法被认为是基类的方法,因此不如接受Convertible的方法好。

这里的原则是,覆盖虚方法是一个可以更改的实现细节,而不是提示编译器选择覆盖方法。

更一般地说,重载解析算法的这些特性旨在帮助缓解各种版本的脆性基类问题。

有关这些设计决策的更多细节,请参阅我关于这个主题的文章:

http://blogs.msdn.com/b/ericlippert/archive/2007/09/04/future-breaking-changes-part-three.aspx

当从基类中删除派生类型参数时,将调用Convert的最派生版本。我没有预料到这种差异,因为我没有预料到Convert抽象版本的接口发生了变化

这个问题是基于一个错误的前提;最派生的版本是not called。程序片段是错误的,因此不能编译,因此两个方法都不会被调用;程序没有运行,因为它没有编译。