Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 扩展方法重写_C#_Extension Methods - Fatal编程技术网

C# 扩展方法重写

C# 扩展方法重写,c#,extension-methods,C#,Extension Methods,假设我有两个班 public class A {...} public class B : A {...} 我想要实现的是覆盖这两种类型的扩展函数 public static void HelperExtension(this A a) {...} public static void HelperExtension(this B b) {...} 我知道它们不是虚拟函数,也不是虚拟函数。然而,我真的很想知道在这种情况下编译器的行为 有没有一种方法可以调用类型B的函数而不解析其类型?或任何

假设我有两个班

public class A {...} 
public class B : A {...}
我想要实现的是覆盖这两种类型的扩展函数

public static void HelperExtension(this A a) {...}
public static void HelperExtension(this B b) {...}
我知道它们不是虚拟函数,也不是虚拟函数。然而,我真的很想知道在这种情况下编译器的行为

有没有一种方法可以调用类型B的函数而不解析其类型?或任何自动解决建议?

这不是覆盖-如果有任何问题,它是超负荷的

这很好-因为签名不同,编译器编译它不会有任何问题,即使在相同的命名空间中也是如此

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


现在:

有没有一种方法可以调用类型B的函数而不解析其类型?或任何自动解决建议

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


这就是为什么大多数LINQ都是在
IEnumerable

上定义的,正如您所说,没有办法只使扩展虚拟化

你可以,但我有一种强烈的感觉,那对你来说没有任何实际用途,这更像是一个有趣的理论解决方案,因为涉及到的工作对于这么简单的事情来说是禁止的

如果有一个固定的、有限数量的可能的子类,您可以使用第一种方法:

public static void HelperExtension(this A a)
{
    B b = a as B;
    if(b != null)
       HelperExtension(b);
    else
       //the rest of the method.
}
如果有很多子类,可以使用
开关
,甚至可以使用
字典
,但这将非常繁琐,难以维护,并且不支持编译时未知的任意继承器

另一种选择是在编译时通过使用
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){...}

我最近遇到了一个类似的问题。我有一个第三方类库,其中包含类的层次结构(比如IBase、Base和Derived,其中IBase实际上是一个接口)

然后,我有一个我的类,它持有对IBase的引用ext。ext的具体类型既可以是基础类型,也可以是派生类型

public class MyClass {
    // other stuff
    public IBase ext;
}
我实际上需要的是一个虚拟方法AddedMethod(),它在IBase中定义并在每个子类中重写,但这是不可行的。因此,可以尝试定义一个包含一组重载扩展方法的类:

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()。这是行不通的:因为扩展方法是静态绑定的,所以不管ext的实际类型如何,都会始终调用第一个方法(即AddedMethod(这个IBase arg))。 通过在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作为其参数。

扩展不是必须是静态的吗?如果它是B对象,但您有对它的引用,是否需要将其解析为第二个扩展方法?毕竟,在A引用上调用虚拟方法将解决B对象上的问题。你控制A类和B类吗?如果是这样的话,你无论如何也不应该使用扩展方法,而是用普通方法修改类。你试过了吗?我试着简化我的实际案例。我厌倦了解析对象类型以找到正确的扩展方法,因为我们的一个库使用了很多扩展方法。我意识到那个图书馆出了问题。IEnumerable是一个很好的例子,类似的实现可以在我的案例中使用,而无需更改应用程序模型,或者至少只需稍作更改。他希望能够做
A=新B();a、 HelperExtension()并让它调用第二个方法而不是第一个方法。我希望有这样的注释,问题是如果我使用类方法而不是扩展,这将被重写。谢谢顺便说一句:)@ozanbora这个答案是不正确的。您不能只是将
virtual
附加到扩展方法上并使其成为虚拟的,但您可以通过其他方式复制该行为。@Servy,我已阅读了所有注释,不幸的是,您的注释是最后一个。你是对的。
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
    }