KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Базы данных » Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю

Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Троелсен Эндрю, "Язык программирования C#9 и платформа .NET5" бесплатно, без регистрации.
Перейти на страницу:

BinaryOp b = new BinaryOp(SimpleMath.Add);

<b>// Вызвать метод Add() косвенно с использованием объекта делегата.</b>

Console.WriteLine(&quot;10 + 10 is {0}&quot;, b(10, 10));

Console.ReadLine();

// Дополнительные определения типов должны находиться

// в конце операторов верхнего уровня.

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

// принимающий два целых числа и возвращающий целое число.

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

На заметку! Вспомните из главы 3, что дополнительные определения типов (делегат

BinaryOp
в этом примере) должны располагаться после всех операторов верхнего уровня.

И снова обратите внимание на формат объявления типа делегата

BinaryOp
; он определяет, что объекты делегата
BinaryOp
могут указывать на любой метод, принимающий два целочисленных значения и возвращающий целочисленное значение (действительное имя метода, на который он указывает, к делу не относится). Здесь мы создали класс по имени
SimpleMath
, определяющий два статических метода, которые соответствуют шаблону, определяемому делегатом B
inaryOp
.

Когда вы хотите присвоить целевой метод заданному объекту делегата, просто передайте имя нужного метода конструктору делегата:

// Создать объект делегата BinaryOp, который

// &quot;указывает&quot; на SimpleMath.Add().

BinaryOp b = new BinaryOp(SimpleMath.Add);

На данной стадии метод, на который указывает делегат, можно вызывать с использованием синтаксиса, выглядящего подобным прямому вызову функции:

// На самом деле здесь вызывается метод Invoke()!

Console.WriteLine(&quot;10 + 10 is {0}&quot;, b(10, 10));

"За кулисами" исполняющая среда вызывает сгенерированный компилятором метод

Invoke()
на вашем производном от
MulticastDelegate
классе. В этом можно удостовериться, открыв сборку в утилите
ildasm.exe
и просмотрев код CIL внутри метода
Main()
:

.method private hidebysig static void Main(string[] args) cil managed

{

  ...

  callvirt   instance int32 BinaryOp::Invoke(int32, int32)

}

Язык C# вовсе не требует явного вызова метода

Invoke()
внутри вашего кода. Поскольку
BinaryOp
может указывать на методы, которые принимают два аргумента, следующий оператор тоже допустим:

Console.WriteLine(&quot;10 + 10 is {0}&quot;, b.Invoke(10, 10));

Вспомните, что делегаты .NET Core безопасны в отношении типов. Следовательно, если вы попытаетесь передать делегату метод, который не соответствует его шаблону, то получите ошибку на этапе компиляции. В целях иллюстрации предположим, что в классе

SimpleMath
теперь определен дополнительный метод по имени
SquareNumber()
, принимающий единственный целочисленный аргумент:

public class SimpleMath

{

  public static int SquareNumber(int a) =&gt; a * a;

}

Учитывая, что делегат

BinaryOp
может указывать только на методы, которые принимают два целочисленных значения и возвращают целочисленное значение, представленный ниже код некорректен и приведет к ошибке на этапе компиляции:

// Ошибка на этапе компиляции! Метод не соответствует шаблону делегата!

BinaryOp b2 = new BinaryOp(SimpleMath.SquareNumber);

Исследование объекта делегата

Давайте усложним текущий пример, создав в классе

Program
статический метод (по имени
DisplayDelegatelnfо()
). Он будет выводить на консоль имена методов, поддерживаемых объектом делегата, а также имя класса, определяющего метод. Для этого организуется итерация по массиву
System.Delegate
, возвращенному методом
GetlnvocationList()
, с обращением к свойствам
Target
и
Method
каждого объекта:

static void DisplayDelegateInfo(Delegate delObj)

{

  // Вывести имена всех членов в списке вызовов делегата.

  foreach (Delegate d in delObj.GetInvocationList())

  {

    Console.WriteLine(&quot;Method Name: {0}&quot;, d.Method);  // имя метода

    Console.WriteLine(&quot;Type Name: {0}&quot;, d.Target);    // имя типа

  }

}

Предполагая, что в метод

Main()
добавлен вызов нового вспомогательного метода:

BinaryOp b = new BinaryOp(SimpleMath.Add);

DisplayDelegateInfo(b);

вывод приложения будет таким:

***** Simple Delegate Example *****

Method Name: Int32 Add(Int32, Int32)

Type Name:

10 + 10 is 20

Обратите внимание, что при обращении к свойству

Target
имя целевого класса (
SimpleMath
) в настоящий момент не отображается. Причина в том, что делегат
BinaryOp
указывает на статический метод, и потому объект для ссылки попросту отсутствует! Однако если сделать методы
Add()
и
Substract()
нестатическими (удалив ключевое слово
static
из их объявлений), тогда можно будет создавать экземпляр класса
SimpleMat
h и указывать методы для вызова с применением ссылки на объект:

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*