从通用抽象类派生的类的C#方法重载问题

我正在研究一个项目,我有一个通用的抽象类型,它接受一个类型参数,它本身是从抽象类型派生的。 如果你想知道为什么我会这样做,请看这个问题 。

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

public abstract class AbstractConverter where U : AbstractConvertible where T : AbstractConverter { public abstract T Convert(U convertible); } public class DerivedConvertibleConverter : AbstractConverter { 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 {} 

在上面的示例中,调用了抽象父级中不存在的转换的重载(并且派生次数较少)。 我希望可以调用来自父类的派生程度最高的版本。

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

 public abstract class AbstractConverter where U : AbstractConvertible { public abstract AbstractConverter Convert(U convertible); } public class DerivedConvertibleConverter : AbstractConverter { 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的派生类型最多的版本。 我不希望这种差异,因为我不希望转换的抽象版本的接口发生变化。 但是,我一定是错的。 谁能解释为什么会出现这种差异? 非常感谢你提前。

在上面的示例中,调用了抽象父级中不存在的转换的重载(并且派生次数较少)。 我希望可以调用来自父类的派生程度最高的版本

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

过载分辨率算法是这样的。 首先,我们列出了您可以调用的所有可访问方法。 覆盖虚方法的方法被认为是声明它们的类的方法,而不是覆盖它们的类。 然后我们过滤掉那些无法将参数转换为forms参数类型的参数。 然后我们过滤掉任何类型的方法都比具有适用方法的任何类型都 。 然后我们确定哪种方法比另一种更好,如果还剩下多个方法的话。

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

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

更一般地,过载分辨率算法的这些特征旨在帮助缓解脆性基类问题的各种版本。

有关这些设计决策的更多详细信息,请参阅我的文章:

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

从基类中删除派生类型参数时,将调用Convert的派生类型最多的版本。 我不希望这种差异,因为我不希望转换的抽象版本的接口发生变化

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