При осмотре делегатов в C# и.NET в целом, я заметил некоторые интересные факты:
Создание делегата в C# создает класс, полученный из MulticastDelegate
с конструктором:
.method public hidebysig specialname rtspecialname instance void .ctor(object 'object', native int 'method') runtime managed { }
Подразумевать, что это ожидает экземпляр и указатель на метод. Все же синтаксис построения делегата в C# предполагает, что это имеет конструктора
new MyDelegate(int () target)
где я могу распознать int ()
как функциональный экземпляр (int *target()
был бы указатель функции в C++). Таким образом, очевидно, компилятор C# выбирает корректный метод от группы метода, определенной именем функции, и создает делегата. Таким образом, первый вопрос был бы, где делает компилятор C# (или Visual Studio, чтобы быть точным) выбирают эту подпись конструктора от? Я не заметил специальных атрибутов или чего-то, что сделает различие. Действительно ли этот своего рода compiler/visualstudio является волшебным? В противном случае T (args) target
конструкция, допустимая в C#? Мне не удалось заставить что-либо с ним компилировать, например:
интервал () предназначается = MyMethod;
недопустимо, так делает что-либо с MyMetod
, например, вызов .ToString()
на нем (хорошо это действительно имеет некоторый смысл, так как это - технически группа метода, но я предполагаю, что должно быть возможно явно выбрать метод путем кастинга, например. (int())MyFunction
. Так все это - просто волшебство компилятора? Рассмотрение конструкции через отражатель показывает еще один синтаксис:
Func $1 CS$0000 = новый Func (пустой указатель, (IntPtr) Foo);
Это согласовывается с демонтированной подписью конструктора, все же это не компилирует!
Одно заключительное интересное примечание то, что классы Delegate
и MulticastDelegate
имейте еще одни группы конструкторов:
Семейство .method hidebysig specialname rtspecialname экземпляр освобождает .ctor (система классов. Введите цель, представьте 'метод' в виде строки), cil управляемый
Где делает переход от экземпляра, и указатель метода на тип и строковое имя метода происходит? Может это быть объясненным runtime managed
ключевые слова в пользовательской подписи конструктора делегата, т.е. время выполнения делает, это - задание здесь?
Править: хорошо, таким образом, я предполагаю, что должен повторно сформулировать то, что я хотел сказать этим вопросом. В основном я предполагаю, что нет только компилятора C# / волшебство CLR, вовлеченное в конструкцию делегата, но также и некоторое волшебство Visual Studio, начиная с зеркальных отражений Intellisense некоторый новый синтаксис при предложении аргументов конструктора, и даже скрывает одного из них (например, Отражатель не использует этот синтаксис и construtor, в этом отношении).
Я задавался вопросом, верно ли это утверждение, и имеет ли функциональный синтаксис экземпляра некоторое более глубокое значение в C# или является им просто некоторый постоянный формат, реализованный частью волшебства Visual Studio для ясности (который имеет смысл, так как оно похоже на недопустимый C#)? Короче говоря, если бы я реализовывал Intellisense, то я должен сделать некоторое волшебство для делегатов, или я мог бы создать предложение некоторым умным механизмом?
ЗАКЛЮЧИТЕЛЬНОЕ РЕДАКТИРОВАНИЕ: таким образом популярное согласие состоит в том, что это - действительно волшебство VS. Наблюдение других примеров (см. комментарий Marc Gravell) такого поведения VS убеждает меня, что это имеет место.
Первый аргумент определяется из ссылки на объект (или null
для статических методов); никакой магии там нет.
Однако второй аргумент - это неуправляемый указатель (собственный int); Короче говоря, нет альтернативного прямого синтаксиса C #, который может использовать этот конструктор - он использует специальную инструкцию IL ( ldftn
) для разрешения функции из метаданных. Однако вы можете использовать Delegate.CreateDelegate
для создания делегатов через отражение. Вы также можете использовать IL emit ( DynamicMethod
и т.д.), но это не весело.
Сначала вы определяете делегат (так Visual Studio узнает сигнатуру целевого метода):
delegate void MyDelegate();
Затем вы создаете экземпляры делегата следующим образом:
MyDelegate method = new MyDelegate({method name});
// If this was the method you wanted to invoke:
void MethodToInvoke()
{
// do something
}
MyDelegate method = new MyDelegate(MethodToInvoke);
C# автоматически выбирает метод, соответствующий сигнатуре делегата.
Редактирование: Когда Visual Studio Intellisense показывает вам предложение int () target
, он показывает вам сигнатуру методов C#, которые вы можете использовать. Компилятор C# переводит представление C# в IL. Реализация IL будет выглядеть иначе, потому что IL не является языком в стиле C, и компилятор C# предоставляет синтаксический сахар, чтобы абстрагироваться от деталей реализации.
Это всего лишь предположение, так что не стреляйте в меня, если я ошибаюсь, но я думаю, что Intellisense получает сигнатуру целевого метода из метода Invoke
, определенного для делегата. Reflector ясно показывает, что метод Invoke
на System.Action
является:
[MethodImpl(0, MethodCodeType=MethodCodeType.Runtime)]
public virtual void Invoke(T obj);
Что совпадает с сигнатурой, предложенной Intellisense. Магия заключается в том, что Intellisense, обнаружив тип делегата, смотрит на метод Invoke
и предлагает конструктор, который принимает цель, соответствующую ему.