让我们来看一下规范。首先,我们必须理解方法调用的规则。大致上,你从实例所指示的类型开始。你往上找可访问的方法,然后进行类型推断和重载解析规则,如果成功就调用该方法。只有在找不到这样的方法时,才会尝试将该方法作为扩展方法处理。所以从§7.5.5.2(扩展方法调用)中可以看到,特别是粗体语句:
在以下方法调用形式中之一:
expr.identifier()
expr.identifier(args)
expr.identifier<typeargs>()
expr.identifier<typeargs>(args)
如果对调用的常规处理未找到适用的方法,则尝试将构造处理为扩展方法调用。
其后面的规则有点复杂,但对于你提供给我们的简单情况来说,非常简单。如果没有适用的实例方法,则会调用扩展方法WindowExtensions.Display(Window, object)
。如果窗口Display
的参数是按钮或可以隐式转换为按钮,则实例方法是适用的。否则,将调用扩展方法(因为从object
派生的所有内容都可以隐式转换为object
)。
所以,除非你遗漏了重要的部分,否则你想做的事情将会起作用。
因此,请考虑以下示例:
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);
int i = 17;
w.Display(i);
string s = "Hello, world!";
w.Display(s);
Button b = new Button();
w.Display(b);
var nab = new NotAButtonButCanBeCastedToAButton();
w.Display(b);
var nabexplict = new NotAButtonButMustBeCastedToAButton();
w.Display(nabexplict);
w.Display((Button)nabexplict);
}
}
这将会打印出来。
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
在控制台中。