5

假设我有两节课。

public class A {...} 
public class B : A {...}

我想要实现的是覆盖这两种类型的扩展函数。

public static void HelperExtension(this A a) {...}
public static void HelperExtension(this B b) {...}

我知道它们不是虚拟功能或表现得像它们。但是我真的很想知道在这种情况下编译器的行为。

有没有办法在不解析其类型的情况下调用 B 类型的函数?或者任何自动解决的建议?

4

3 回答 3

5

这不是压倒一切的——它是重载,如果有的话。

很好 - 因为签名不同,编译器编译它不会有任何问题,即使在同一个命名空间中。

但是,将调用哪种扩展方法取决于变量的确切类型。


现在:

有没有办法在不解析其类型的情况下调用 B 类型的函数?或者任何自动解决的建议?

没有铸造这是不可能的。扩展绑定到正在扩展的确切类型,因此您需要具有确切的类型才能在其上调用扩展。

这就是为什么大多数 LINQ 都是在IEnumerable<T>.

于 2013-03-15T14:42:41.723 回答
2

正如您所说,没有办法只使扩展成为虚拟。

您可以通过静态方法自己实现整个虚拟方法模式,但我有一种强烈的感觉,这对您没有任何实际用途,它更像是一个有趣的理论解决方案,因为所涉及的工作对于这么简单的事情来说是令人望而却步的。

如果有固定的、有限数量的可能子类,您可以让第一种方法具有以下内容:

public static void HelperExtension(this A a)
{
    B b = a as B;
    if(b != null)
       HelperExtension(b);
    else
       //the rest of the method.
}

如果您有很多子类,您可以使用 aSwitch甚至 a Dictionary<Type, Action<A>>,但这会很乏味,难以维护,并且不支持编译时未知的任意继承者。

另一种选择是在编译时通过使用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){...}
于 2013-03-15T14:48:14.170 回答
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 中定义并在每个后代类中重写的虚拟方法 AdditionalMethod(),但这是不可行的。因此,可能会想定义一个包含一组重载扩展方法的类:

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()。这不起作用:因为扩展方法是静态绑定的,所以总是调用第一个方法(即 AdditionalMethod(this 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 类添加一个以 Derived2 作为参数的重载的 innerAddedMethod()。

于 2013-06-10T13:43:39.660 回答