我们假设我有两节课。
public class A {...}
public class B : A {...}
我想要实现的是覆盖两种类型的扩展函数。
public static void HelperExtension(this A a) {...}
public static void HelperExtension(this B b) {...}
我知道它们不是虚函数或行为类似于它们。但是我真的很想知道这种情况下编译器的行为
有没有办法在不解析类型的情况下调用类型B的函数?或者任何自动解决建议?
答案 0 :(得分:5)
这不是覆盖 - 它是重载,如果有的话。
没关系 - 由于签名不同,编译器在编译时也不会有任何问题,即使在相同的命名空间中也是如此。
但是,将调用哪种扩展方法取决于变量的确切类型。
现在:
有没有办法在不解析类型的情况下调用类型B的函数?或者任何自动解决建议?
没有施法,这是不可能的。扩展名绑定到正在扩展的确切类型,因此您需要具有确切的类型才能在其上调用扩展名。
这就是为什么大多数LINQ都是在IEnumerable<T>
上定义的。
答案 1 :(得分:2)
正如你所说,没有办法让扩展成为虚拟。
你可以implement the entire virtual method pattern yourself through static methods但我有一种强烈的感觉,这对你没有任何实际用处,它更像是一个有趣的理论解决方案,因为所涉及的工作对于这么简单的事情是禁止的。
如果存在固定的,有限数量的可能子类,则第一种方法可能具有以下内容:
public static void HelperExtension(this A a)
{
B b = a as B;
if(b != null)
HelperExtension(b);
else
//the rest of the method.
}
如果你有很多子类,你可以使用Switch
甚至是Dictionary<Type, Action<A>>
,但它会很繁琐,难以维护,并且不支持在编译时不知道的任意继承者。 / p>
另一种选择是通过使用dynamic
在编译时基本上利用编译器的功能。我强烈建议尽可能避免它,但在这种特殊情况下,它允许你在A
上有一个公共扩展,为每个子类型提供一堆私有静态方法(具有不同的名称),然后是单一调度电话:
public static void HelperExtension(this A a)
{
ExtenstionImplementation((dynamic)a);
}
private static void ExtenstionImplementation(A a){...}
private static void ExtenstionImplementation(B a){...}
private static void ExtenstionImplementation(C a){...}
答案 2 :(得分:0)
我最近遇到了类似的问题。我有一个包含类层次结构的第三方类库(比如IBase,Base和Derived,其中IBase实际上是一个接口)。
public interface IBase {...}
public class Base : IBase {...}
public class Derived : Base {...}
然后,我有一个我的类,它持有IBase的参考分机。 ext的具体类型可以是Base和Derived。
public class MyClass {
// other stuff
public IBase ext;
}
我真正需要的是在IBase中定义并在每个后代类中重写的虚方法AddedMethod(),但这不可行。因此,人们可能想要定义一个包含一组重载扩展方法的类:
public static class MyExtensions
{
public static void AddedMethod(this IBase arg) {...}
public static void AddedMethod(this Base arg) {...}
public static void AddedMethod(this Derived arg) {...}
}
然后,在MyClass对象上调用ext.AddedMethod()。这不起作用:因为扩展方法是静态绑定的,所以总是调用第一个方法(即AddedMethod(此IBase arg)),而不管ext的实际类型。 可以通过在IBase上定义单个扩展方法,然后使用反射来选择私有静态方法的正确实例来绕过该问题,该方法的参数类型与传递给扩展方法的实际类型相匹配:
public static class MyExtensions
{
// just one extension method
public static void AddedMethod(this IBase arg){
// get actual argument type
Type itsType = arg.GetType();
// select the proper inner method
MethodInfo mi = typeof(MyExtensions).GetMethod("innerAddedMethod",
BindingFlags.NonPublic | BindingFlags.Static,
null,
new Type[] { itsType },
null);
// invoke the selected method
if (mi != null) {
mi.Invoke(null, new object[] { arg });
}
}
private static void innerAddedMethod(Base arg) {
// code for Base type arg
}
private static void innerAddedMethod(Derived arg) {
// code for Derived type arg
}
是否应将新的派生类Derived2添加到IBase层次结构中,我们必须简单地向MyExtensions类添加一个重载的innerAddedMethod(),它将Derived2作为其参数。