Extension methods overloading in C#, does it work?

后端 未结 5 760
遥遥无期
遥遥无期 2020-12-11 17:27

Having a class that has a method, like this:

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

is it possible

5条回答
  •  暖寄归人
    2020-12-11 17:49

    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:

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

    expr.identifier()

    expr.identifier(args)

    expr.identifier()

    expr.identifier(args)

    if the normal processing of the invocation finds no applicable methods, an attempt is made to process the construct as an extension method invocation.

    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
        }
    }
    

    This will print

    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.

提交回复
热议问题