Мне было просто интересно узнать, как методы расширения подключаются к классу Original. Я знаю, что в IL-коде он дает вызов Статическому методу, но как он это делает и почему он не прерывает инкапсуляцию.
Как подключаются методы расширения
Ответ 1
Методы расширения задаются путем размещения ключевого слова this
перед первым параметром статического метода:
public static void SomeExtension(this string s)
{
...
}
Это просто синтаксический сахар для украшения метода System.Runtime.CompilerServices.ExtensionAttribute:
[Extension]
public static void SomeExtension(string s)
{
...
}
Когда компилятор видит этот атрибут, он знает, чтобы перевести вызов метода расширения на соответствующий вызов статического метода, передав экземпляр в качестве первого параметра.
Поскольку вызовы - это просто обычные вызовы статических методов, нет возможности разбить инкапсуляцию; методы, как и все статические методы, имеют доступ только к общедоступным интерфейсам расширенных типов.
Ответ 2
Они не "подключаются".
IDE Visaul Studio просто заставляет его выглядеть так, как показано, показывая их в списках intellisense.
Компилятор "знает", как обращаться со ссылками, чтобы сделать правильные вызовы методов с правильными параметрами.
Это просто синтаксический сахар - методы - это просто статические методы в отдельном статическом классе. Используя модификатор this
, компилятор "знает", чтобы добавить ExtensionAttribute
, чтобы отметить его как метод расширения.
Поскольку методы расширения делают не, фактически меняют класс и могут обращаться к ним только из открытых элементов, инкапсуляция сохраняется.
От MSDN:
Методы расширения - это особый тип статического метода, но они называются , как будто они были методами экземпляра расширенного типа.
(акцент мой)
Ответ 3
Методы расширения - это просто синтаксический сахар, они просто статические методы. Вы можете получить доступ к публичным полям или свойствам в них, как и обычные статические методы.
Ответ 4
Ключевым элементом является то, что метод экземпляра класса принципиально не отличается от статического метода. С одной небольшой деталью у них есть скрытый аргумент. Например, метод String.IndexOf(char) действительно выглядит так: CLR:
public static int IndexOf(string thisRef, char value) {
// etc...
}
Аргумент thisRef - это то, что поставляет строковую ссылку всякий раз, когда вы используете это в своем коде или получаете доступ к члену класса. Как вы можете видеть, это очень маленький шаг от метода расширения до метода экземпляра. Для поддержки этой функции в среде CLR не было никаких изменений.
Еще одно незначительное отличие заключается в том, что компилятор испускает код, который проверяет, является ли это null для метода экземпляра, но не делает этого для метода расширения. Вы можете вызвать метод расширения для нулевого объекта. Хотя это может выглядеть как функция, на самом деле это ограничение, вызванное методом расширения, фактически не являющимся членом класса.
Внутри CLR хранит список методов для класса MethodTable. Методы расширения не находятся в них, не позволяя компилятору испускать IL-код callvirt, "трюк", который он использует для получения дешевой нулевой проверки. Явно испускающий код, чтобы сделать нулевую проверку, было возможно, но они решили не делать этого. Не совсем уверен, почему.
Другим автоматическим следствием этого является то, что метод расширения не может быть виртуальным.
Ответ 5
Думаю, вам стоит взглянуть на http://go.microsoft.com/fwlink/?LinkId=112388