【发布时间】:2011-04-06 20:59:40
【问题描述】:
我正在做一个项目,我有一个通用抽象类型,它接受一个类型参数,该类型参数本身是从抽象类型派生的。如果您想知道我为什么要这样做,请参阅this question。
我遇到了一个有趣的问题,即在抽象类中定义的派生类中重载方法。这是一个代码示例:
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 的抽象版本的接口会发生变化。但是,我一定是错的。谁能解释为什么会出现这种差异?非常感谢您。
【问题讨论】:
-
您的第二个代码 sn-p 不应该编译顺便说一句,因为 Convert 方法不是协变的。 (即,它应该返回一个
AbstractConverter<DerivedConvertible>,而不是更多派生的DerivedConvertibleConverted) -
谢谢你,马克。你是对的。但是,在编译之前,IDE 会在该状态下解析正确版本的方法。如果我将方法修复为具有正确的返回类型
AbstractConverter<DerivedConvertible>,则会出现同样的问题,导致调用派生较少的方法。也许这个问题没有变通方法。 -
有一个简单的解决方法,也就是说(例如在第一个 sn-p 中)
(this as AbstractConverter<DerivedConvertibleConverter, DerivedConvertible>).Convert(convertible));在 .ctor 中。主要问题是两个 Convert 方法都被调用匹配。我不确定编译器用于最佳匹配的标准,但似乎第二种方法更好匹配,因为 DerivedConvertible 不直接从 AbstractConvertible 继承。它唯一的直接基类是Convertible,与第二种方法完全匹配。 -
当代码不正确时,IDE 会做出最好的猜测,它可以给出错误的程序。当你给它一个非法程序时,你不能从IDE的猜测中推断出什么是合法。它是错误恢复启发式方法,而不是展望未来,看你将如何解决错误!
-
在这种特殊情况下,IDE 可能会猜测“覆盖”是错误,并假设您将删除它,因为该方法实际上并未覆盖任何内容;它不能,因为返回类型不匹配。如果 IDE 假定它不是覆盖,那么重载解析可能会选择它。
标签: c# overloading generics