Подводя итоги, отметим, что определение типа делегата C# дает в результате запечатанный класс со сгенерированным компилятором методом, в котором типы параметров и возвращаемые типы основаны на объявлении делегата. Базовый шаблон может быть приближенно описан с помощью следующего псевдокода:

// Это лишь псевдокод!

public sealed class ИмяДелегата : System.MulticastDelegate

{

  public возвращаемоеЗначениеДелегата

      Invoke(всеВходныеRefиOutПараметрыДелегата);

}

<p id="AutBody_Root447">Базовые классы System.MulticastDelegate и System.Delegate</p>

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

<p id="AutBody_Root448">Пример простейшего делегата</p>

На первый взгляд делегаты могут показаться несколько запутанными. Рассмотрим для начала простой проект консольного приложения (по имени 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");

Перейти на страницу:

Похожие книги