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

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 232 233 234 235 236 237 238 239 240 ... 642

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, определяющий два статических метода, которые соответствуют шаблону, определяемому делегатом BinaryOp.

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

// Создать объект делегата 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(), принимающий единственный целочисленный аргумент:

(window.adrunTag = window.adrunTag || []).push({v: 1, el: 'adrun-4-390', c: 4, b: 390})

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 из их объявлений), тогда можно будет создавать экземпляр класса SimpleMath и указывать методы для вызова с применением ссылки на объект:

1 ... 232 233 234 235 236 237 238 239 240 ... 642
На этой странице вы можете бесплатно читать книгу Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю бесплатно.
Похожие на Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю книги

Оставить комментарий