Я создал метод расширения для ASP.NET MVC ViewPage, например:
public static class ViewExtensions
{
public static string Method<T>(this ViewPage<T> page) where T : class
{
return "something";
}
}
При вызове этого метода из представления (производного от ViewPage
) я получаю сообщение об ошибке « CS0103: имя« Метод »не существует в текущем контексте », если я не использую this
ключевое слово для его вызова:
<%: Method() %> <!-- gives error CS0103 -->
<%: this.Method() %> <!-- works -->
Почему this
требуется ключевое слово? Или без него работает, а что-то упускаю?
(Думаю, должен быть дубликат этого вопроса, но мне не удалось его найти)
Обновление :
Как говорит Бен Робинсон , синтаксис для вызова методов расширения - это просто сахар компилятора. Тогда почему компилятор не может автоматически проверять методы расширения базовых типов текущего типа без использования ключевого слова this?
this
ключевое слово), я спрашиваю, зачем этоthis
ключевое слово требуется. Я обновил свой вопрос.Ответы:
Пара очков:
Во-первых, предлагаемая функция (неявное "this." При вызове метода расширения) не нужна . Методы расширения были необходимы для того, чтобы понимание запросов LINQ работало так, как мы хотели; получатель всегда указывается в запросе, поэтому нет необходимости поддерживать неявную поддержку this, чтобы LINQ работал.
Во-вторых, эта функция работает против более общего дизайна методов расширения: а именно, эти методы расширения позволяют вам расширять тип, который вы не можете расширить самостоятельно , либо потому, что это интерфейс, и вы не знаете его реализацию, либо потому, что вы это делаете. знаете реализацию, но не имеете исходного кода.
Если вы находитесь в сценарии , где вы используете метод расширения для типа внутри этого типа , то вы действительно имеете доступ к исходному коду. Тогда почему вы вообще используете метод расширения? Вы можете написать метод экземпляра самостоятельно, если у вас есть доступ к исходному коду расширенного типа, и тогда вам вообще не нужно использовать метод расширения! Затем ваша реализация может воспользоваться преимуществами доступа к частному состоянию объекта, чего не могут добиться методы расширения.
Упрощение использования методов расширения внутри типа, к которому у вас есть доступ, поощряет использование методов расширения вместо методов экземпляра. Методы расширения - это здорово, но обычно лучше использовать метод экземпляра, если он у вас есть.
С учетом этих двух моментов на разработчика языка больше не ложится бремя объяснения, почему эта функция не существует. Теперь вам нужно объяснить, почему это должно происходить . С функциями связаны огромные затраты. Эта функция не является необходимой и работает против заявленных целей разработки методов расширения; почему мы должны брать на себя расходы по его внедрению? Объясните, какой привлекательный и важный сценарий позволяет использовать эту функцию, и мы рассмотрим возможность ее реализации в будущем. Я не вижу убедительного и важного сценария, который бы это оправдал, но, возможно, есть один, который я пропустил.
источник
this
она требуется. 2: Почему я вызываю метод расширения из расширенного типа? В приведенном примере я добавляю несколько удобных методов к базовому классу (ViewPage) и вызываю его из производных классов. Это избавляет от необходимости создавать общий базовый класс для всех моих представлений. Кстати: я согласен с тем, что использовать метод расширения из расширенного типа неудобно, но снова посмотрите пример с MVC ViewPage.ICrossProductable
, и вы определяете метод расширения для этого вызываемого интерфейсаGetProduct
. Очень простой пример, но я часто нахожу его полезным. Однако это не лучший подход во всех случаях.Без него компилятор просто видит его как статический метод в статическом классе, который принимает страницу в качестве первого параметра. т.е.
// without 'this' string s = ViewExtensions.Method(page);
vs.
// with 'this' string s = page.Method();
источник
В методах экземпляра this неявно передается каждому методу прозрачно, поэтому вы можете получить доступ ко всем членам, которые он предоставляет.
Методы расширения статичны. Вызывая
Method()
вместоthis.Method()
илиMethod(this)
, вы не говорите компилятору, что передать методу.Вы можете сказать: «Почему он просто не понимает, что такое вызывающий объект, и не передает его в качестве параметра?»
Ответ заключается в том, что методы расширения статичны и могут быть вызваны из статического контекста, где нет this.
Я предполагаю, что они могли бы проверить это во время компиляции, но, честно говоря, это, вероятно, большая работа с очень небольшой отдачей. И, честно говоря, я не вижу особой пользы в том, чтобы убрать некоторую часть явности вызовов методов расширения. Тот факт, что они могут ошибаться, например, в методах, означает, что иногда они могут быть совершенно не интуитивно понятными (например, исключение NullReferenceExceptions не генерируется). Иногда мне кажется, что им следовало ввести новый оператор стиля «прямая передача» для методов расширения.
источник
Важно отметить, что существуют различия между методами расширения и обычными методами. Думаю, вы только что столкнулись с одним из них.
Я приведу вам пример еще одного отличия: довольно легко вызвать метод расширения для
null
ссылки на объект. К счастью, обычными методами это сделать намного сложнее. (Но это можно сделать. IIRC, Джон Скит продемонстрировал, как это сделать, манипулируя кодом CIL.)static void ExtensionMethod(this object obj) { ... } object nullObj = null; nullObj.ExtensionMethod(); // will succeed without a NullReferenceException!
При этом я согласен с тем, что
this
вызов метода расширения кажется немного нелогичным . В конце концов, в идеале метод расширения должен «ощущаться» и вести себя так же, как и нормальный.Но на самом деле методы расширения больше похожи на синтаксический сахар, добавленный поверх существующего языка, чем на раннюю базовую функцию, которая хорошо вписывается в язык во всех отношениях.
источник
null
? Может быть практически любой ссылочный тип, как он узнает, какие методы доступныnull
?String
логически ведут себя как значения и могут иметь разумное значение по умолчанию, когда null (например, .net может последовательно рассматривать нулевую ссылку статического типаstring
как пустую строку, а не делать это только спорадически). Необходимость использовать статические методы для таких вещейif (!String.IsNullOrEmpty(stringVar))
просто ужасно.Поскольку метод расширения не существует с классом ViewPage. Вам нужно сообщить компилятору, для чего вы вызываете метод расширения. Помните, что
this.Method()
это просто сахар компилятораViewExtensions.Method(this)
. Точно так же нельзя просто вызвать метод расширения в середине любого класса по имени метода.источник
this
ключевого слова?Я работаю над плавным API и столкнулся с той же проблемой. Несмотря на то, что у меня есть доступ к классу, который я расширяю, я все же хотел, чтобы логика каждого из свободных методов находилась в их собственных файлах. Ключевое слово «this» было очень неинтуитивным, пользователи продолжали думать, что метод отсутствовал. Что я сделал, так это сделал мой класс частичным классом, который реализовал нужные мне методы вместо использования методов расширения. Я не увидел в ответах упоминания о частичностях. Если у вас есть этот вопрос, то партиалы могут быть лучшим вариантом.
источник