// (1) ParamToken : Name : x flags: [none]
// (2) ParamToken : Name : y flags: [none] //
// Method #3
// -------------------------------------------------------
// MethodName: BeginInvoke
// ReturnType: Class System.IAsyncResult
// 4 Arguments
// Argument #1: I4
// Argument #2: I4
// Argument #3: Class System.AsyncCallback
// Argument #4: Object
// 4 Parameters
// (1) ParamToken : Name : x flags: [none]
// (2) ParamToken : Name : y flags: [none]
// (3) ParamToken : Name : callback flags: [none]
// (4) ParamToken : Name : object flags: [none]
//
// Method #4
// -------------------------------------------------------
// MethodName: EndInvoke
// ReturnType: I4 (int32)
// 1 Arguments
// Argument #1: Class System.IAsyncResult
// 1 Parameters
// (1) ParamToken : Name : result flags: [none]
Как видите, в сгенерированном компилятором классе BinaryOp определены три открытых метода. Главным методом в .NET Core является Invoke(), т.к. он используется для вызова каждого метода, поддерживаемого объектом делегата, в синхронной манере; это означает, что вызывающий код должен ожидать завершения вызова, прежде чем продолжить свою работу. Довольно странно, но синхронный метод Invoke() может не нуждаться в явном вызове внутри вашего кода С#. Вскоре будет показано, что Invoke() вызывается "за кулисами", когда вы применяете соответствующий синтаксис С#.
На заметку! Несмотря на то что методы BeginInvoke() и EndInvoke() генерируются, они не поддерживаются при запуске вашего кода под управлением .NET Core. Это может разочаровывать, поскольку в случае их использования вы получите ошибку не на этапе компиляции, а во время выполнения.
Так благодаря чему же компилятор знает, как определять метод Invoke()? Для понимания процесса ниже приведен код сгенерированного компилятором класса BinaryOp (полужирным курсивом выделены элементы, указанные в определении типа делегата):
sealed class BinaryOp : System.MulticastDelegate
{
public int Invoke(int x, int y);
...
}
Первым делом обратите внимание, что параметры и возвращаемый тип для метода Invoke() в точности соответствуют определению делегата BinaryOp.
Давайте рассмотрим еще один пример. Предположим, что определен тип делегата, который может указывать на любой метод, возвращающий значение string и принимающий три входных параметра типа System.Boolean:
public delegate string MyDelegate (bool a, bool b, bool c);
На этот раз сгенерированный компилятором класс можно представить так:
sealed class MyDelegate : System.MulticastDelegate
{
public string Invoke(bool a, bool b, bool c);
...
}
Делегаты могут также "указывать" на методы, которые содержат любое количество параметров out и ref (а также параметры типа массивов, помеченные с помощью ключевого слова params). Пусть имеется следующий тип делегата:
public delegate string MyOtherDelegate(out bool a, ref bool b, int c);
Сигнатура метода Invoke() выглядит вполне ожидаемо.