Подтвердить что ты не робот

Делегаты в .NET: как они построены?

При проверке делегатов на С# и .NET в целом я заметил некоторые интересные факты:

Создание делегата в С# создает класс, полученный из MulticastDelegate, с помощью конструктора:

.method public hidebysig specialname rtspecialname instance 
   void .ctor(object 'object', native int 'method') runtime managed { }

означает, что он ожидает экземпляр и указатель на этот метод. Однако синтаксис построения делегата в С# предполагает, что он имеет конструктор

new MyDelegate(int () target)

где я могу распознать int () как экземпляр функции (int *target() будет указателем функции в С++). Таким образом, очевидно, что компилятор С# выбирает правильный метод из группы методов, определяемой именем функции, и создает делегат. Итак, первый вопрос: где компилятор С# (или Visual Studio, если быть точным) выбирает эту подпись конструктора? Я не заметил никаких особых атрибутов или чего-то, что бы делало различие. Это что-то вроде магии компилятора /visualstudio? Если нет, является ли конструкция T (args) target действительной в С#? Мне не удалось получить что-либо с ним для компиляции, например:

int() target = MyMethod;

является недопустимым, поэтому делает что-либо с MyMetod, например. вызывая .ToString() на нем (хорошо это имеет смысл, так как это технически группа методов, но я полагаю, что должно быть возможно явно выделить метод путем кастинга, например (int())MyFunction. Так что все это чисто компилятор магия? Глядя на конструкцию через отражатель, появляется еще один синтаксис:

Func CS $1 $0000 = new Func (null, (IntPtr) Foo);

Это согласуется с дизассемблированной сигнатурой конструктора, но это не скомпилируется!

Наконец, интересно отметить, что классы Delegate и MulticastDelegate имеют еще один набор конструкторов:

.method family hidebysig specialname rtspecialname instance      void.ctor(класс System.Type target, string 'method') cil managed

Где происходит переход от указателя экземпляра и метода к типу и имени метода? Может ли это быть объяснено ключевыми словами runtime managed в пользовательской сигнатуре конструктора делегата, т.е. Работает ли среда выполнения здесь?

EDIT: хорошо, поэтому, я думаю, я должен переформулировать то, что я хотел сказать по этому вопросу. В основном я предполагаю, что в создании делегатов не только используется С# -компилятор/CLR-магия, но также и магия Visual Studio, поскольку Intellisense выводит какой-то новый синтаксис, предлагая аргументы конструктора и даже скрывая один из них (например, Reflector не использует этот синтаксис и конструктор, если на то пошло).

Мне было интересно, истинно ли это утверждение и имеет ли синтаксис экземпляра функции более глубокий смысл в С# или это просто какой-то постоянный формат, реализованный магической частью Visual Studio для ясности (что имеет смысл, так как выглядит недействительным С#)? Короче говоря, если бы я выполнял Intellisense, должен ли я делать какую-то магию для делегатов или могу ли я построить предложение каким-то умным механизмом?

ОКОНЧАТЕЛЬНЫЙ РЕДАКТИРОВАНИЕ: так что популярный консенсус в том, что это действительно волшебство В.С. Видя другие примеры (см. Комментарий Марка Гравелла) о том, что такое поведение VS, убеждает меня в том, что это так.

4b9b3361

Ответ 1

Первый аргумент разрешен из ссылки на объект (или null для статических методов); там нет магии.

Повторяем второй аргумент - это неуправляемый указатель (native int); Короче говоря, нет альтернативного прямого синтаксиса С#, который может использовать этот конструктор - он использует определенную инструкцию IL (ldftn), чтобы разрешить эту функцию из метаданных. Однако вы можете использовать Delegate.CreateDelegate для создания делегатов посредством отражения. Вы также можете использовать испускание IL (DynamicMethod и т.д.), Но это не весело.

Ответ 2

Сначала вы определяете делегата (так 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);

С# автоматически выбирает метод, соответствующий сигнатуре делегата.

Изменить: Когда Visual Studio Intellisense показывает вам предложение int () target, оно покажет вам подпись методов С#, которые вы можете использовать. Компилятор С# переводит представление С# в IL. Реализация IL будет выглядеть по-другому, потому что IL не является языком стиля C, а компилятор С# обеспечивает синтаксический сахар, чтобы абстрагировать детали реализации.

Ответ 3

Это просто предположение, поэтому не стреляйте в меня, если я ошибаюсь, но я думаю, что Intellisense получает подпись для целевого метода из метода Invoke, определенного на делегате. Отражатель ясно показывает, что метод Invoke на System.Action<T>:

[MethodImpl(0, MethodCodeType=MethodCodeType.Runtime)]
public virtual void Invoke(T obj);

Это то же самое, что и предложение подписи, предлагаемое Intellisense. Магия Intellisense, обнаруживая тип делегата, смотрит на метод Invoke и предлагает конструктор, который принимает цель, которая соответствует ему.