Подводя итоги, отметим, что определение типа делегата C# дает в результате запечатанный класс со сгенерированным компилятором методом, в котором типы параметров и возвращаемые типы основаны на объявлении делегата. Базовый шаблон может быть приближенно описан с помощью следующего псевдокода:
// Это лишь псевдокод!
public sealed class
{
public
Invoke(
}
Базовые классы System.MulticastDelegate и System.Delegate
Итак, когда вы строите тип с применением ключевого слова delegate, то неявно объявляете тип класса, производного от System.MulticastDelegate. Данный класс предоставляет своим наследникам доступ к списку, который содержит адреса методов, поддерживаемых типом делегата, а также несколько дополнительных методов (и перегруженных операций) для взаимодействия со списком вызовов. Ниже приведены избранные методы класса System.MulticastDelegate:
public abstract class MulticastDelegate : Delegate
{
// Возвращает список методов, на которые "указывает" делегат.
public sealed override Delegate[] GetInvocationList();
// Перегруженные операции.
public static bool operator ==
(MulticastDelegate d1, MulticastDelegate d2);
public static bool operator !=
(MulticastDelegate d1, MulticastDelegate d2);
// Используются внутренне для управления списком методов,
// поддерживаемых делегатом.
private IntPtr _invocationCount;
private object _invocationList;
}
Класс System.MulticastDelegate получает дополнительную функциональность от своего родительского класса System.Delegate. Вот фрагмент его определения:
public abstract class Delegate : ICloneable, ISerializable
{
// Методы для взаимодействия со списком функций.
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);
// Перегруженные операции.
public static bool operator ==(Delegate d1, Delegate d2);
public static bool operator !=(Delegate d1, Delegate d2);
// Свойства, открывающие доступ к цели делегата.
public MethodInfo Method { get; }
public object Target { get; }
}
Имейте в виду, что вы никогда не сможете напрямую наследовать от таких базовых классов в своем коде (попытка наследования приводит к ошибке на этапе компиляции). Тем не менее, когда вы используете ключевое слово delegate, то тем самым неявно создаете класс, который "является" MulticastDelegate. В табл. 12.1 описаны основные члены, общие для всех типов делегатов.
Пример простейшего делегата
На первый взгляд делегаты могут показаться несколько запутанными. Рассмотрим для начала простой проект консольного приложения (по имени SimpleDelegate), в котором применяется определенный ранее тип делегата BinaryOp. Ниже показан полный код с последующим анализом:
// SimpleMath.cs
namespace 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.cs
using System;
using SimpleDelegate;
Console.WriteLine("***** Simple Delegate Example *****\n");