Язык программирования C#9 и платформа .NET5
...}Делегаты могут также "указывать" на методы, которые содержат любое количество параметров
иout(а также параметры типа массивов, помеченные с помощью ключевого словаref). Пусть имеется следующий тип делегата:paramspublic delegate string MyOtherDelegate(out bool a, ref bool b, int c);Сигнатура метода
выглядит вполне ожидаемо.Invoke()Подводя итоги, отметим, что определение типа делегата C# дает в результате запечатанный класс со сгенерированным компилятором методом, в котором типы параметров и возвращаемые типы основаны на объявлении делегата. Базовый шаблон может быть приближенно описан с помощью следующего псевдокода:
// Это лишь псевдокод!public sealed class <i>ИмяДелегата</i> : System.MulticastDelegate{public <i>возвращаемоеЗначениеДелегата</i>Invoke(<i>всеВходныеRefиOutПараметрыДелегата</i>);}Базовые классы System.MulticastDelegate и System.Delegate
Итак, когда вы строите тип с применением ключевого слова
, то неявно объявляете тип класса, производного отdelegate. Данный класс предоставляет своим наследникам доступ к списку, который содержит адреса методов, поддерживаемых типом делегата, а также несколько дополнительных методов (и перегруженных операций) для взаимодействия со списком вызовов. Ниже приведены избранные методы классаSystem.MulticastDelegate:System.MulticastDelegatepublic abstract class MulticastDelegate : Delegate{<b> // Возвращает список методов, на которые "указывает" делегат.</b>public sealed override Delegate[] GetInvocationList();<b> // Перегруженные операции.</b>public static bool operator ==(MulticastDelegate d1, MulticastDelegate d2);public static bool operator !=(MulticastDelegate d1, MulticastDelegate d2);<b> // Используются внутренне для управления списком методов,</b><b> // поддерживаемых делегатом.</b>private IntPtr _invocationCount;private object _invocationList;}Класс
получает дополнительную функциональность от своего родительского классаSystem.MulticastDelegate. Вот фрагмент его определения:System.Delegatepublic abstract class Delegate : ICloneable, ISerializable{<b> // Методы для взаимодействия со списком функций.</b>public static Delegate Combine(params Delegate[] delegates);public static Delegate Combine(Delegate a, Delegate b);public static Delegate Remove(Delegate source, Delegate value);public static Delegate RemoveAll(Delegate source, Delegate value);<b> // Перегруженные операции.</b>public static bool operator ==(Delegate d1, Delegate d2);public static bool operator !=(Delegate d1, Delegate d2);<b> // Свойства, открывающие доступ к цели делегата.</b>public MethodInfo Method { get; }public object Target { get; }}Имейте в виду, что вы никогда не сможете напрямую наследовать от таких базовых классов в своем коде (попытка наследования приводит к ошибке на этапе компиляции). Тем не менее, когда вы используете ключевое слово
, то тем самым неявно создаете класс, который "является"delegate. В табл. 12.1 описаны основные члены, общие для всех типов делегатов.MulticastDelegateПример простейшего делегата
На первый взгляд делегаты могут показаться несколько запутанными. Рассмотрим для начала простой проект консольного приложения (по имени
), в котором применяется определенный ранее тип делегатаSimpleDelegate. Ниже показан полный код с последующим анализом:BinaryOp// SimpleMath.csnamespace SimpleDelegate{// Этот класс содержит методы, на которые// будет указывать BinaryOp.public class SimpleMath{public static int Add(int x, int y) => x + y;public static int Subtract(int x, int y) => x - y;}}// Program.csusing System;using SimpleDelegate;Console.WriteLine("***** Simple Delegate Example *****\n");<b>// Создать объект делегата BinaryOp, который</b><b>// "указывает" на SimpleMath.Add().</b>
