扩展方法在C#中超载,它的工作原理?它的、工作原理、方法

2023-09-03 05:03:06 作者:玖卿

有一个类有一个方法,像这样的:

Having a class that has a method, like this:

class Window {
    public void Display(Button button) {
        // ...
    }
}

是有可能的方法与另外一个是比较广泛的,像这样的过载:

is it possible to overload the method with another one that is more broad, like this:

class WindowExtensions {
    public void Display(this Window window, object o) {
        Button button = BlahBlah(o);
        window.Display(button);
    }
}

什么,当我试图碰巧的是,我有无限递归。有没有一种方法,使这项工作?欲被称为扩展方法只有当其它方法不能被称为

What happened when I tried is that I have infinite recursion. Is there a way to make that work? I want the extension method to be called only when the other method can't be called.

推荐答案

让我们去规范。首先,我们要了解的方法调用的规则。粗略地说,你开始与你正在试图调用一个方法的实例指出的类型。你走了继承链寻找一种使用方法。然后,你做你的类型推断和重载决策规则,并调用方法如果成功。仅当没有找到这样的方法,你尝试处理方法作为扩展方法。因此,从§7.5.5.2(扩展方法调用)看,特别是粗体的语句:

Let's go to the specification. First, we have to understand the rules for method invocations. Roughly, you start with the type indicated by the instance you are trying to invoke a method on. You walk up the inheritance chain looking for an accessible method. Then you do your type inference and overload resolution rules and invoke the method if that succeeds. Only if no such method is found do you try to process the method as an extension method. So from §7.5.5.2 (Extension method invocations) see, in particular, the bolded statement:

在的一种形式的方法调用(第7.5.5.1节)

In a method invocation (§7.5.5.1) of one of the forms

expr.identifier()

expr.identifier(参数)

expr.identifier< typeargs>()

expr.identifier< typeargs>(参数)

如果调用的正常处理没有发现适用的方法,试图处理结构作为扩展方法调用。

之外的规则变得有点复杂,但简单的情况下,你已经presented给我们来说很简单。如果没有适用的实例方法,然后扩展方法 WindowExtensions.Display(窗口对象)将被调用。实例方法是适用的,如果参数 Window.Display 是一个按钮或者是隐含浇注到一个按钮。否则,扩展方法将被调用(因为一切都源于对象隐式强制转换为一个对象)。

The rules beyond that get a little complicated, but for the simple case you've presented to us it's quite simple. If there is no applicable instance method then the extension method WindowExtensions.Display(Window, object) will be invoked. The instance method is applicable if the parameter to Window.Display is a button or is implicitly castable to a button. Otherwise, the extension method will be invoked (because everything that derives from object is implicitly castable to an object).

所以,除非你是留下了一个重要的一点,你正在做的工作会是什么。

So, unless there is an important bit that you are leaving out, what you are trying to do will work.

那么,请看下面的例子:

So, consider the following example:

class Button { }
class Window {
    public void Display(Button button) {
        Console.WriteLine("Window.Button");
    }
}

class NotAButtonButCanBeCastedToAButton {
    public static implicit operator Button(
        NotAButtonButCanBeCastedToAButton nab
    ) {
        return new Button();
    }
}

class NotAButtonButMustBeCastedToAButton {
    public static explicit operator Button(
        NotAButtonButMustBeCastedToAButton nab
    ) {
        return new Button();
    }
}

static class WindowExtensions {
    public static void Display(this Window window, object o) {
        Console.WriteLine("WindowExtensions.Button: {0}", o.ToString());
        Button button = BlahBlah(o);
        window.Display(button);
    }
    public static Button BlahBlah(object o) {
        return new Button();
    }
}

class Program {
    static void Main(string[] args) {
        Window w = new Window();
        object o = new object();
        w.Display(o); // extension
        int i = 17;
        w.Display(i); // extension
        string s = "Hello, world!";
        w.Display(s); // extension
        Button b = new Button();
        w.Display(b); // instance
        var nab = new NotAButtonButCanBeCastedToAButton();
        w.Display(b); // implicit cast so instance
        var nabexplict = new NotAButtonButMustBeCastedToAButton();
        w.Display(nabexplict); // only explicit cast so extension
        w.Display((Button)nabexplict); // explictly casted so instance
    }
}

这将打印

WindowExtensions.Button: System.Object
Window.Button
WindowExtensions.Button: 17
Window.Button
WindowExtensions.Button: Hello, world!
Window.Button
Window.Button
Window.Button
WindowExtensions.Button: NotAButtonButMustBeCastedToAButton
Window.Button
Window.Button

在控制台上。

on the console.