Почему вы не можете напрямую ссылаться на методы расширения?

Может кто-нибудь объяснить мне, почему в следующем случае 3-й вызов DoSomething недействителен? (Сообщение об ошибке "Имя" DoSomething "не существует в текущем контексте" )

public class A { }
public class B : A
{
    public void WhyNotDirect()
    {
        var a = new A();
        a.DoSomething();  // OK
        this.DoSomething();  // OK
        DoSomething(); // ?? Why Not
    }
}
public static class A_Ext
{
    public static void DoSomething(this A a)
    {
        Console.WriteLine("OK");
    }
}

Ответ 1

Методы расширения по-прежнему являются статическими, а не истинными вызовами экземпляров. Для этого вам понадобится конкретный контекст, используя синтаксис метода экземпляра (из Методы расширения (Руководство по программированию на С#))

В вашем коде вы вызываете расширение метод с синтаксисом метода экземпляра. Однако промежуточный язык (IL), сгенерированный компилятором переводит ваш код в статический метод. Следовательно принцип инкапсуляции не действительно нарушается. По факту, методы расширения не могут получить доступ частные переменные типа расширение.

Таким образом, хотя обычно оба синтаксиса будут работать, второй не имеет явного контекста, и кажется, что генерируемый IL не может получить контекст неявно.

Ответ 2

Методы расширения можно вызвать, как и другие статические методы.

Измените его на A_Ext.DoSomething(this).

Если вы спрашиваете, почему он неявно вызывается в this, ответ заключается в том, что способ написания спецификации. Я бы предположил, что причина в том, что вызов его без квалификатора будет слишком вводить в заблуждение.

Ответ 3

Потому что DoSomething принимает параметр.

DoSomething(a) будет законным.

Edit

Я немного читал этот вопрос.

Поскольку ваш вызов является обычным статическим методом, а не методом расширения, вам нужно указать имя класса.

Итак, A_Ext.DoSomething(a); будет работать.

Если вы вызываете его как обычный статический метод, применяются все те же правила.

Второй вариант работает, потому что B inhetits A, и поэтому вы все еще называете его как метод расширения, но третий не делает.

извините за первую версию выше, которая работает не. Я оставлю его, чтобы оставить комментарий соответствующим.

Ответ 4

DoSomething требуется экземпляр A, чтобы сделать что-либо, и без квалификатора компилятор не может видеть, какой DoSomething вам нужно вызвать. Он не знает, чтобы проверить A_Ext для вашего метода, если вы не квалифицируете его с помощью this.