День пятидесятый. #ЗаметкиНаПолях

Управление цепочками делегатов

В C# можно создавать и управлять цепочками делегатов при помощи операторов += и -=. Цепочку делегатов можно вызвать так же, как и единичный делегат. При этом будут вызваны все делегаты цепочки по очереди. Это достаточно удобно и подходит для большинства сценариев. Однако у этого метода есть ряд ограничений. Например, сохраняется только последнее из возвращаемых значений, возвращаемых методами. Получить остальные значения нельзя. Кроме того, если один из делегатов в цепочке выбрасывает исключение, работа цепочки останавливается.

В качестве альтернативы можно использовать метод GetInvokationList класса MulticastDelegate. Он возвращает массив ссылок на делегаты в цепочке. Следующий код безопасно выполняет делегаты из цепочки и сохраняет их возвращаемые значения:

private delegate string MyDelegate();



private static string Method1() => "Method1";

private static string Method2() => throw new Exception("Exception");

private static string Method3() => "Method3";



static void Main(string[] args)

{

MyDelegate getResult = null;

getResult += new MyDelegate(Method1);

getResult += new MyDelegate(Method2);

getResult += new MyDelegate(Method3);



Console.WriteLine(GetAllResults(getResult));

}



private static string GetAllResults(MyDelegate result)

{

if (result == null) return null;



var report = new StringBuilder();

var delegates = result.GetInvocationList();

foreach (MyDelegate del in delegates)

{

try

{

//пытаемся выполнить метод, сохраняя его результат

report.AppendFormat("{0}\n", del());

}

catch (Exception ex)

{

//обрабатываем ошибки метода

//здесь component – класс владелец метода

var component = del.Target;

report.AppendFormat(

" Ошибка при получении результата из метода {0}{1}: {2}\n",

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

del.Method.Name,

ex.Message);

}

}



return report.ToString();

}



Источник: Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 17.