Давайте перейдем к спецификации. Во-первых, мы должны понять правила для вызова методов. Грубо говоря, вы начинаете с типа, указанного экземпляром, для которого вы пытаетесь вызвать метод. Вы идете вверх по цепочке наследования в поисках доступного метода. Затем вы делаете вывод типа и правила разрешения перегрузки и вызываете метод, если это удается. Только если такой метод не найден, вы пытаетесь обработать метод как метод расширения. Так из §7.5.5.2 (вызовы метода расширения), в частности, см. Жирный оператор:
В вызове метода (§7.5.5.1) одной из форм
expr.identifier()
expr.identifier(args)
expr.identifier<typeargs>()
expr.identifier<typeargs>(args)
если при обычной обработке вызова не найдено подходящих методов, делается попытка обработать конструкцию как вызов метода расширения .
Сложившиеся правила немного усложняются, но для простого случая, который вы нам представили, все довольно просто. Если подходящего метода экземпляра не существует, будет вызван метод расширения WindowExtensions.Display(Window, object)
. Метод экземпляра применим, если параметр Window.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); // 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
на консоли.