Почему ключевое слово "this" требуется для вызова метода расширения изнутри расширенный класс

Я создал метод расширения для ASP.NET MVC ViewPage, например:

public static class ViewExtensions
{
    public static string Method(this ViewPage page) where T : class
    {
        return "something";
    }
}

При вызове этого метода из представления (производного от ViewPage ) я получаю сообщение об ошибке « CS0103: имя« Метод »не существует в текущем контексте », если я не использую this ключевое слово для его вызова:

<%: Method() %> 
<%: this.Method() %> 

Почему необходимо это ключевое слово ? Или это работает без него, но я что-то упускаю?

(я думаю, что должен быть дубликат этого вопроса, но я не смог его найти)

Обновление :

Как Бен Робинсон говорит , что синтаксис для вызова методов расширения - просто сахар компилятора. Тогда почему t компилятор автоматически проверяет методы расширения базовых типов текущего типа, не запрашивая ключевое слово this?

75
задан Community 23 May 2017 в 12:34
поделиться

5 ответов

Пара замечаний:

Во-первых, предлагаемая функция (неявное "this." При вызове метода расширения) не нужна . Методы расширения были необходимы для того, чтобы понимание запросов LINQ работало так, как мы хотели; получатель всегда указывается в запросе, поэтому нет необходимости поддерживать неявную поддержку this, чтобы LINQ работал.

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

Если вы находитесь в сценарии, в котором вы используете метод расширения для типа внутри этого типа , тогда у вас действительно есть доступ к исходному коду. Почему тогда вы вообще используете метод расширения? Вы можете написать метод экземпляра самостоятельно, если у вас есть доступ к исходному коду расширенного типа, а затем вы этого не сделаете. Не обязательно использовать метод расширения! Затем ваша реализация может воспользоваться преимуществами доступа к частному состоянию объекта, чего не могут добиться методы расширения.

Упрощение использования методов расширения внутри типа, к которому у вас есть доступ, поощряет использование методов расширения вместо методов экземпляра. Методы расширения - это здорово, но обычно лучше использовать метод экземпляра, если он у вас есть.

Учитывая эти два момента, разработчик языка больше не обязан объяснять, почему эта функция не существует. Теперь вам нужно объяснить, почему он должен . С функциями связаны огромные затраты. Эта функция не является необходимой и работает против заявленных проектных целей методов расширения; почему мы должны брать на себя расходы по его внедрению? Объясните, какой привлекательный и важный сценарий позволяет использовать эту функцию, и мы рассмотрим возможность ее реализации в будущем. Я не вижу убедительного и важного сценария, который бы это оправдал, но, возможно, есть один, который я пропустил.

49
ответ дан 24 November 2019 в 11:43
поделиться

В методах экземпляра this неявно передается каждому методу прозрачно, поэтому вы можете получить доступ ко всем членам, которые он предоставляет.

Методы расширения статичны. Вызывая Method () вместо this.Method () или Method (this) , вы не сообщаете компилятору, что передать методу.

Вы могли бы сказать: «Почему он просто не понимает, что такое вызывающий объект, и не передает его в качестве параметра?»

Ответ заключается в том, что методы расширения являются статическими и могут быть вызваны из статического контекста, где есть не это'.

Я думаю, они могли бы проверить это во время компиляции, но, честно говоря, это, вероятно, большая работа с очень небольшой отдачей. И, честно говоря, я не вижу особой пользы в том, чтобы убрать некоторую часть явности вызовов методов расширения. Тот факт, что они могут ошибаться, например, в методах, означает, что иногда они могут быть совершенно неинтуитивными (например, исключение NullReferenceExceptions не генерируется). Иногда мне кажется, что им следовало ввести новый оператор стиля «прямая передача» для методов расширения.

6
ответ дан 24 November 2019 в 11:43
поделиться

Без него компилятор просто видит его как статический метод в статическом классе, который принимает страницу в качестве первого параметра. то есть

// without 'this'
string s = ViewExtensions.Method(page);

vs.

// with 'this'
string s = page.Method();
8
ответ дан 24 November 2019 в 11:43
поделиться

Поскольку метод расширения не существует с классом ViewPage. Вам нужно сообщить компилятору, для чего вы вызываете метод расширения. Помните, что this.Method () - это просто сахар компилятора для ViewExtensions.Method (this) . Точно так же нельзя просто вызвать метод расширения в середине любого класса по имени метода.

1
ответ дан 24 November 2019 в 11:43
поделиться

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

Я приведу вам пример другого различия: довольно легко вызвать метод расширения для нулевой ссылки на объект. К счастью, обычными методами это сделать намного сложнее. (Но это можно сделать. IIRC, Джон Скит продемонстрировал, как это сделать, манипулируя кодом CIL.)

static void ExtensionMethod(this object obj) { ... }

object nullObj = null;
nullObj.ExtensionMethod();  // will succeed without a NullReferenceException!

При этом я согласен, что кажется немного нелогичным, что this требуется для вызова метод расширения. В конце концов, в идеале метод расширения должен «ощущаться» и вести себя так же, как и нормальный.

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

3
ответ дан 24 November 2019 в 11:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: