Литмир - Электронная Библиотека
A
A

// Этот делегат может указывать на любой метод, который принимает

// два целочисленных значения и возвращает целочисленное значение.

public delegate int BinaryOp(int x, int y);

Когда компилятор C# обрабатывает тип делегата, он автоматически генерирует запечатанный (

sealed
) класс, производный от
System.MulticastDelegate
. Этот класс (в сочетании со своим базовым классом
System.Delegate
) предоставляет необходимую инфраструктуру для делегата, которая позволяет хранить список методов, подлежащих вызову в будущем. Например, если вы изучите делегат
BinaryOp
с помощью утилиты
ildasm.exe
, то обнаружите показанные ниже детали (вскоре вы построите полный пример):

//     -------------------------------------------------------

//     TypDefName: SimpleDelegate.BinaryOp

//     Extends   : System.MulticastDelegate

//     Method #1

//     -------------------------------------------------------

//             MethodName: .ctor

//             ReturnType: Void

//             2 Arguments

//                     Argument #1:  Object

//                     Argument #2:  I

//     Method #2

//     -------------------------------------------------------

//             MethodName: Invoke

//             ReturnType: I4

//             2 Arguments

//                     Argument #1:  I4

//                     Argument #2:  I4

//             2 Parameters

//                     (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 <b>BinaryOp</b> : System.MulticastDelegate

{

  public <b>int</b> Invoke(<b>int x, int y</b>);

...

}

Первым делом обратите внимание, что параметры и возвращаемый тип для метода

Invoke()
в точности соответствуют определению делегата
BinaryOp
.

Давайте рассмотрим еще один пример. Предположим, что определен тип делегата, который может указывать на любой метод, возвращающий значение

string
и принимающий три входных параметра типа
System.Boolean
:

public delegate string MyDelegate (bool a, bool b, bool c);

На этот раз сгенерированный компилятором класс можно представить так:

sealed class <b>MyDelegate</b> : System.MulticastDelegate

{

  public <b>string</b> Invoke(<b>bool a, bool b, bool c</b>);

234
{"b":"847442","o":1}