扩展方法是静态方法,您不能覆盖静态方法。您也不能使用静态/扩展方法“覆盖”实际实例方法。
您必须明确使用优化的扩展。或者通过隐式引用您自己的扩展的命名空间而不是System.Linq
.
或者显式检查扩展中的类型并根据运行时类型调用正确的类型。
这似乎是一个比扩展方法更适合继承的问题。如果您需要基于运行时类型的不同功能,则将基方法设为虚拟并在派生类中重写它。
我发现扩展方法在这方面存在很多混乱。你必须明白它们不是 mixin,它们实际上并没有被注入到类中。它们只是编译器识别的语法糖,并“允许”您像常规实例方法一样执行它。想象一下它不是一个扩展方法,只是一个静态方法:
public static void BlowHorn (IBoat boat) {
Console.WriteLine ("Patched on horn for {0}: TWEET", boat.GetType().Name);
}
您将如何从IBoat
执行?你不能。您唯一能做的就是将类型检查放入此静态方法中,或者编写一些动态方法调用代码,或者使用dynamic
C# 4 中的块或早期版本中的反射。
为了使这一点更清楚,请查看以下代码System.Linq.Enumerable
反射器类:
public static TSource ElementAt<TSource>(this IEnumerable<TSource> source,
int index)
{
TSource current;
if (source == null)
{
throw Error.ArgumentNull("source");
}
IList<TSource> list = source as IList<TSource>;
if (list != null)
{
return list[index];
}
// ...
}
这是.NET Framework 中的核心扩展方法之一。它允许通过显式检查参数是否实现来进行优化IList<T>
。除此之外,它无法知道底层具体类型是否实际上支持索引访问。你必须以同样的方式这样做;创建另一个界面,例如IHorn
或其他东西,然后在您的扩展中检查是否IBoat
还实现了IHorn
,与Enumerable
类在这里。
如果您不控制任一代码IBoat
类或扩展方法,那么你就不走运了。如果这样做,那么使用多接口继承、显式类型检查或动态代码,这些都是您的选择。