пятница, 18 мая 2012 г.

.NET C# - Multicast Delegates (Part 1)

Все делегаты в C# наследуются от MulticastDelegate класса (который в свою очередь наследуется от базового класса делегатов Delegate). MulticastDelegate содержит в себе массив объектов Delegate. Это означает то, что любой делегат может содержать в себе ссылки на множество методов. Для того чтобы получить список всех методов в каком-либо объекте делегата, необходимо вызвать метод GetInvocationList(). Перейдем к примерам.

Предположим, что у нас есть три Action делегата, которые мы хотим объединить в один делегат и затем его вызвать, что поведет за собой вызов всех трех методов:
Action<string> helloMessage = mes => Console.WriteLine("Hello " + mes);
Action<string> howAreYouMessage = mes => Console.WriteLine("How are you " + mes);
Action<string> byeMessage = mes => Console.WriteLine("Bye " + mes);
Объединяем с помощью оператора "+"
var multicast = helloMessage + howAreYouMessage + byeMessage;
multicast("Harry");
Консоль отобразит следующие результаты:
----------------------------
Hello Harry
How are you Harry
Bye Harry

 ----------------------------
Тем самым мы доказали, что любой делегат может содержать в себе любое количество методов. Это очень важная концепция для понятия механизма событий.
Еще важно отметить тот факт, что эти операции статически типизированы, что полностью исключает возникновение ошибок в рантайме. К чему я это? Дело в том, что вместо оператора "+" можно воспользоваться статическим методом Delegate класса Combine(), который возвращает сцепленный объект Delegate. Т.е. в контексте предыдущего примера, присвоение делегату multicast трех методов будет выглядеть следующим образом
var multicast = (Action<string>)Delegate.Combine(helloMessage,howAreYouMessage,byeMessage);
Здесь мы видим явное приведение типа к Action<string> и потерю проверок в момент компиляции (т.е. теперь проверки в рантайме). Почему? Предположим такое развитие событий
Action<string> helloMessage = mes => Console.WriteLine("Hello " + mes);
Func<int,int> powered = num => num * num;
var multicast = (Action<string>)Delegate.Combine(helloMessage,powered);
Бамс! На момент компиляции все прекрасно, но здесь будет явная ошибка во время выполнения, т.к. мы пытаемся преобразовать делегат типа Func<int,int> в Action<string>!

Комментариев нет:

Отправить комментарий