Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
271 views
Welcome To Ask or Share your Answers For Others

1 Answer

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<typeargs>()

expr.identifier<typeargs>(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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...