Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю
BinaryOp b = new BinaryOp(SimpleMath.Add);
<b>// Вызвать метод Add() косвенно с использованием объекта делегата.</b>
Console.WriteLine("10 + 10 is {0}", b(10, 10));
Console.ReadLine();
// Дополнительные определения типов должны находиться
// в конце операторов верхнего уровня.
// Этот делегат может указывать на любой метод,
// принимающий два целых числа и возвращающий целое число.
public delegate int BinaryOp(int x, int y);
На заметку! Вспомните из главы 3, что дополнительные определения типов (делегат
BinaryOp
И снова обратите внимание на формат объявления типа делегата
BinaryOp
BinaryOp
SimpleMath
inaryOp
Когда вы хотите присвоить целевой метод заданному объекту делегата, просто передайте имя нужного метода конструктору делегата:
// Создать объект делегата BinaryOp, который
// "указывает" на SimpleMath.Add().
BinaryOp b = new BinaryOp(SimpleMath.Add);
На данной стадии метод, на который указывает делегат, можно вызывать с использованием синтаксиса, выглядящего подобным прямому вызову функции:
// На самом деле здесь вызывается метод Invoke()!
Console.WriteLine("10 + 10 is {0}", b(10, 10));
"За кулисами" исполняющая среда вызывает сгенерированный компилятором метод
Invoke()
MulticastDelegate
ildasm.exe
Main()
.method private hidebysig static void Main(string[] args) cil managed
{
...
callvirt instance int32 BinaryOp::Invoke(int32, int32)
}
Язык C# вовсе не требует явного вызова метода
Invoke()
BinaryOp
Console.WriteLine("10 + 10 is {0}", b.Invoke(10, 10));
Вспомните, что делегаты .NET Core безопасны в отношении типов. Следовательно, если вы попытаетесь передать делегату метод, который не соответствует его шаблону, то получите ошибку на этапе компиляции. В целях иллюстрации предположим, что в классе
SimpleMath
SquareNumber()
public class SimpleMath
{
public static int SquareNumber(int a) => 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("Method Name: {0}", d.Method); // имя метода
Console.WriteLine("Type Name: {0}", 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