Студопедия

КАТЕГОРИИ:

АстрономияБиологияГеографияДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРиторикаСоциологияСпортСтроительствоТехнологияФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника


Расширенное управление цепочкой делегатов




Вы уже поняли, как строить цепочки объектов-делегатов и как вызывать все объекты в таком списке. Поскольку метод Invoke типа делегата включает код, итеративно перечисляющий все элементы массива, вызываются все элементы цепочки. Видно, что это очень простой алгоритм. Хотя для большинства сценариев достаточно и такого простого алгоритма, у него много ограничений. Например, отбрасываются все значения, возвращаемые методами обратного вызова, кроме последнего. Остальные значения, возвращаемые методами обратного вызова, невозможно получить при использовании простого алгоритма, но это ограничение — не единственное. А если один из вызванных делегатов генерирует исключение или надолго заблокируется? Поскольку алгоритм последовательно вызывает все делегаты цепочки, «проблема» с одним из делегатов в цепочке остановит вызов остальных. Ясно, что такой алгоритм ненадежен.

Для ситуаций, в которых такого алгоритма недостаточно, класс MulticastDelegate предлагает экземплярный метод GetlnvocationList, позволяющий явно вызвать любой из делегатов цепочки по любому алгоритму, соответствующему вашим потребностям:

public abstract class MulticastDelegate : Delegate

{

// Создает массив делегатов, в котором

// каждый элемент соответствует делегату цепочки.

public sealed override Delegated GetlnvocationList();

}

Метод GetlnvocationList принимает объект, производный от MulticastDelegate, и возвращает массив ссылок на массив ссылок на Delegate, в котором каждая ссылка указывает на один из объектов-делегатов цепочки.

Код GetlnvocationList создает массив и инициализирует его элементами, каждый из которых ссылается на один делегат в цепочке; в конце возвращается ссылка на массив. Если значение поля _invocationList равно null, возвращаемый массив содержит один элемент, который ссылается на единственный делегат цепочки, на экземпляр самого делегата.

Можно без труда написать алгоритм, явно вызывающий каждый объект массива:

using System;

using System.Text;

// Определяем компонент Light.

internal sealed class Light

{

// Этот метод возвращает состояние объекта Light.

public String SwitchPosition()

{

return "The light is off";

}

}

// Определяем компонент Fan.

internal sealed class Fan

{

// Этот метод возвращает состояние объекта Fan.

public String Speed()

{

throw new InvalidOperationException("The fan broke due to overheating");

}

}

// Определяем компонент Speaker.

internal sealed class Speaker

{

// Этот метод возвращает состояние объекта Speaker.

public String Volume()

{

return "The volume is loud";

}

}

 

public sealed class Program

{

// Определение делегатов, позволяющих запрашивать состояние компонента.

private delegate String GetStatus();

public static void Main()

{

// Объявляем пустую цепочку делегатов.

GetStatus getStatus = null;

// Создаем три компонента и добавляем в цепочку делегатов

// методы для проверки их состояния.

getStatus += new GetStatus(new Light().SwitchPosition);

getStatus += new GetStatus(new Fan().Speed);

getStatus += new GetStatus(new Speaker().Volume);

// Отображаем сводный отчет, отражающий

// состояние трех компонентов.

Console.WriteLine(GetComponentStatusReport(getStatus));

Console.ReadLine();

}

// Метод, запрашивающий несколько компонентов

// и возвращающий отчет об их состоянии.

private static String GetComponentStatusReport(GetStatus status)

{

// Если цепочка пуста, то делать нечего.

if (status == null)

return null;

// Построить отчет о состоянии.

StringBuilder report = new StringBuilder();

// Получаем массив, где каждый элемент - это делегат из цепочки.

Delegate[] arrayOfDelegates = status.GetInvocationList();

// Итеративно обрабатываем все делегаты массива.

foreach (GetStatus getStatus in arrayOfDelegates)

{

try

{

// Получаем строку с состоянием компонента и добавляем в отчет.

report.AppendFormat("{0}{1}{1}", getStatus(), Environment.NewLine);

}

catch (InvalidOperationException e)

{

// Генерируем в отчете запись об ошибке для этого компонента.

Object component = getStatus.Target;

report.AppendFormat(

"Failed to get status from {1}{2}{0}Error: {3}{0}{0}",

Environment.NewLine,

((component == null) ? "" : component.GetType() + "."),

getStatus.Method.Name,

e.Message

);

}

}

// Вернуть сводный отчет вызывающему коду.

return report.ToString();

}

}

 

Скомпоновав и запустив этот код, мы увидим:

 

The light is off

Failed to get status from Fan.Speed

Error: The fan broke due to overheating

The volume is loud

 

Упрощение синтаксиса работы с делегатами в С#

Большинство программистов считает, что работать с делегатами слишком обременительно. Причина в очень сложном синтаксисе. Возьмем к примеру такую строку кода:

button1.Click += new EventHandler(button1_Click);

где button1.Click — это метод, выглядящий примерно так:

void button1_Click(Object sender, EventArgs e)

{

// Кнопка щелкнута - нужно выполнять соответствующие действия...

}

Идея первой строки кода — зарегистрировать адрес метода button1_Click в элементе управления «кнопка» с тем, чтобы по щелчку кнопки вызывался этот метод. Большинству программистов кажется совершенно неестественным создавать объект-делегат EventHandler только для того, чтобы определить адрес метода button1_Click. Однако создание объекта-делегата EventHandler необходимо CLR, так как этот объект служит оберткой, которая обеспечивает вызов метода со строгим соблюдением безопасности типов. Обертка также поддерживает вызов экземплярных методов и создание цепочек делегатов. К сожалению, большинство программистов не хочет думать о таких деталях. Программисты предпочли бы записать приведенный выше код так:

button1.Click += button1_Click;

К счастью, компилятор С# от Microsoft поддерживает несколько способов упрощения синтаксиса при работе с делегатами. Сейчас я об этом расскажу поподробнее, но, прежде чем начать, сделаю одно важное замечание. То, что вы сейчас узнаете, — всего лишь ряд упрощений синтаксиса в C#, которые облегчают задачу программистам по созданию IL-кода, который необходим для нормальной работы CLR и других языков программирования с делегатами. Это также означает, что все сказанное ниже относится исключительно к C# — другие компиляторы скорее всего не поддерживают такой упрощенный синтаксис делегатов.

 


Поделиться:

Дата добавления: 2015-04-21; просмотров: 69; Мы поможем в написании вашей работы!; Нарушение авторских прав





lektsii.com - Лекции.Ком - 2014-2024 год. (0.005 сек.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав
Главная страница Случайная страница Контакты