return x – у;
}
}
Если не использовать синтаксис анонимных методов, то мы должны обработать событие ComputationComplete так, как показано ниже.
class Program {
static void Main(string[] args) {
SimpleMath m = new SimpleMath;
m.ComputationFinished += new SimpleMath.MathMessage(ComputationFinishedHandler);
Console.WriteLine("10 + 10 равно {0}", m.Add(10, 10));
Console.ReadLine;
}
static void ComputationFinishedHandler(string msg) { Console.WriteLine(msg); }
}
Но можно зарегистрировать программу обработки событий для конкретного события и так, как показано ниже (в остальном программный код изменений не претерпевает).
m.ComputationFinished += ComputationFinishedHandler;
Обратите внимание на то, что мы не создаем непосредственно соответствующий тип делегата, а просто указываем метод, который соответствует ожидаемой сигнатуре делегата (в данном случае это метод, не возвращающий ничего и получающий один объект типа System.String). Ясно, что компилятор C# при этом должен обеспечить типовую безопасность. Если метод ComputationFinishedHandler не получает System.String и не возвращает void, то вы получите сообщение об ошибке компиляции.
Можно и явно конвертировать обработчик события в экземпляр соответствующего делегата. Это может оказаться полезным тогда, когда нужно получить соответствующий делегат, использующий заранее определенный метод. Например:
// .NET 2.0 допускает преобразование обработчиков событий
// в соответствующие делегаты.
SimpleMath.MathMessage mmDelegate = (SimpleMath.MathMessage)ComputationFinishedHandler;
Console.WriteLine(mmDelegate.Method);
Если выполнить этот программный код, то заключительный оператор Console.WriteLine напечатает сигнатуру ComputationFinishedHandler, как показано на рис. 8.9.
Рис. 8.9. Можно извлечь делегат из соответствующего обработчика события
Исходный код. Проект AnonymousMethods размещен в подкаталоге, соответствующем главе 8.
Резюме
В этой главе был рассмотрен ряд подходов, позволяющих реализовать возможность двухстороннего взаимодействия объектов. Сначала было рассмотрено использование
Затем было рассмотрено ключевое слово C# delegate, которое используется для непрямого построения классов, производных от System.MulticastDelegate. Как выяснилось, делегат представляет собой объект, хранящий список методов, доступных для вызова. При этом вызовы, могут быть синхронными (они выполняются с помощью метода Invoke) или асинхронными (они выполняются с помощью методов BeginInvoke и EndInvoke). Асинхронная природа типов делегата .NET будет рассмотрена позже.
Ключевое слово C# event при использовании с типом делегата позволяет упростить процесс отправки сообщений событий вызывающим объектам. Как показывает генерируемый CIL-код, модель событий .NET сводит ситуацию к скрытым вызовам типов System.Delegate/System.MulticastDelegate. В этой связи ключевое слово C# event оказывается необязательным и просто экономит время при наборе текста программы.
Новая возможность, появившаяся в C# 2005 и получившая название
ГЛАВА 9. Специальные приемы построения типов
В этой главе вы расширите горизонты вашего понимания языка C#, рассмотрев ряд более сложных (но весьма полезных) синтаксических конструкций. Сначала мы с вами выясним, как использовать метод индексатора. Этот механизм в C# позволяет строить пользовательские типы, обеспечивающие доступ к внутренним подтипам на основе синтаксиса массивов. Научившись строить методы индексатора, вы затем узнаете, как перегружать различные операции (+, -, ‹, › и т.д.) и явно или неявно создавать пользовательские подпрограммы преобразования типов (а также узнаете, зачем это может понадобиться).