Прошел курс. Получил код Dreamspark. Ввожу код на сайте, пишет: Срок действия этого кода проверки уже истек. Проверьте, правильно ли введен код. У вас осталось две попытки. Вы также можете выбрать другой способ проверки или предоставить соответствующие документы, подтверждающие ваш академический статус.
Как активировать код? |
Интерфейсы, делегаты, события в C#
Методы DynamicInvoke() и GetInvocationList()
Этот метод позволяет вызывать отдельные члены, адресуемые списком объекта-делегата, и задавать требуемые аргументы. Если член списка не имеет аргументов, то в качестве параметра метода используется null, иначе - массив параметров адресуемого члена.
Мы убедились, что объявление ссылки на объект-делегат прописывает только прототип методов, которые корректно может адресовать эта ссылка. Сам делегат как объект создается при заполнении списка адресуемыми функциями. Но при формировании списка в него добавляются только имена методов. Это приемлемо, если вызываются функции с пустой сигнатурой.
using System; namespace Test { class ShowPerson { // Объявляем функцию с аргументами public static void Handler(string name, int age) { Console.WriteLine("Сотрудник {0}, возраст {1}", name, age); } } // Вызывающая сторона class MyClass { public static string Title = "Вызов методов с параметрами"; // Объявляем делегат как член класса delegate void MyDelegate(string name, int age); public MyClass() { // Создаем и заполняем объект-делегат MyDelegate del = new MyDelegate(ShowPerson.Handler); // Добавляем другие ссылки int count = 3; for (int i = 1; i < count; i++) { del += ShowPerson.Handler; } // Вызываем цепочку методов с одинаковым параметром del("Иванов", 21); } } // Запуск class Program { static void Main() { // Настройка консоли Console.Title = MyClass.Title; Console.ForegroundColor = ConsoleColor.White; Console.CursorVisible = false; Console.WindowWidth = 30; Console.WindowHeight = 4; new MyClass();// Исполняем Console.ReadLine(); } } }Листинг 10.13 . Делегирование вызова методов с параметрами
Здесь просматривается очень важный вывод, что все зарегистрированные в делегате методы стороннего класса получают, при вызове их с помощью делегата, одинаковую входную информацию.
А как быть, если с помощью делегата нужно адресовать методы, имеющие разные значения параметров. Вот тут-то и может пригодиться рассматриваемый метод делегата.
public object DynamicInvoke(params object[ ] args)
Но есть еще одна важная проблема, которую можно решить с помощью метода DynamicInvoke(), это надежность кода при адресации вызовов методов посредством делегата. Дело в том, что любой из цепочки метод при традиционном вызове может дать сбой. В результате система выдаст исключение и прервет вызовы остальных методов списка. Исключение мы можем обработать, но только для списка в целом, если не будем контролировать индивидуально каждый член списка делегата. Например, в приведенном фрагменте кода что-то успеет выполниться до выброса исключения, а что-то нет:
try { del(null, 0); } catch { }
Эти проблемы решает метод DynamicInvoke() совместно с GetInvocationList(), как показано в следующем примере
using System; namespace Test { class ShowPerson { // Функция с аргументами public static void Handler(string name, int age) { Console.WriteLine("Сотрудник {0}, возраст {1}", name, age); } // Проблемная функция с нормальным прототипом public static void ProblemHandler(string name, int age) { // Преднамеренно выбрасываем исключение throw new Exception(); } } // Вызывающая сторона class MyClass { public static string Title = "Применение DynamicInvoke()"; // Объявляем делегат delegate void MyDelegate(string name, int age); public MyClass() { // // Формируем список объекта-делегата // // Добавляем в список один проблемный метод MyDelegate del = new MyDelegate(ShowPerson.ProblemHandler); // Добавляем еще три нормальных метода int count = 3; for (int i = 0; i < count; i++) { del += ShowPerson.Handler; } object[] param = new object[2];// Объявили массив для параметров int j = 0; // Объявили и инициализировали счетчик // Перебираем список вызовов делегата, включая и вызов проблемного метода foreach (Delegate d in del.GetInvocationList()) { // Индивидуально формируем параметры методов switch (j) { case 0:// Можно и не задавать, все равно для проблемного метода! param[0] = "Мистер X"; param[1] = 99; break; // Для вызовов нормального метода case 1: param[0] = "Иванов"; param[1] = 21; break; case 2: param[0] = "Петров"; param[1] = 22; break; case 3: param[0] = "Сидоров"; param[1] = 23; break; } j++; // Счетчик // Защищенно вызываем адресуемые методы индивидуально try { d.DynamicInvoke(param); } catch (Exception exc) { string str = d.Method.Name; Console.WriteLine("Сбой метода {0}!!!", str); str = exc.Message; // Системное сообщение // Разбиваем длинное сообщение пополам int pos = str.Length / 2; pos = str.IndexOf(' ', pos);// От средины первый пробел Console.WriteLine("\"" + // Экранируем кавычки str.Substring(0, pos) + Environment.NewLine + str.Substring(pos + 1) + "\""); // Экранируем кавычки Console.WriteLine(); // Отделяем сообщение } } } } // Запуск class Program { static void Main() { // Настройка консоли Console.Title = MyClass.Title; Console.ForegroundColor = ConsoleColor.White; Console.CursorVisible = false; Console.WindowWidth = 32; Console.WindowHeight = 8; new MyClass();// Исполняем Console.ReadLine(); } } }Листинг 10.14 . Применение метода DynamicInvoke()
Перегруженные операторы 'operator ==' и 'operator !='
Эти операторы позволяют подтвердить или опровергнуть абсолютную идентичность списков функций сравниваемых делегатов.
using System; namespace Test { class Handler { // Функции public void Handler1() { } public void Handler2() { ; } } // Вызывающая сторона class MyClass { public static string Title = "Применение операторов '==' и '!='"; // Объявляем делегат delegate void MyDelegate(); // Объявляем ссылки на делегаты как // поля для видимости в методах класса MyDelegate del0, del1; public MyClass() { // Создаем объект Handler obj = new Handler(); // Формируем список вызовов объекта-делегата del0 = new MyDelegate(obj.Handler1); del0 += new MyDelegate(obj.Handler2); // Еще один делегат с тем же списком вызовов del1 = new MyDelegate(obj.Handler1); del1 += obj.Handler2; // Упрощенный синтаксис // Сравниваем делегаты с полность совпадающими списками Compare(); // Делегат прежним содержимым, но в другом порядке del1 = new MyDelegate(obj.Handler2); del1 += obj.Handler1; // Упрощенный синтаксис // Сравниваем делегаты с одинаковым содержимым, но разным порядком Compare(); // Изменяем содержимое одного из делегатов del0 -= obj.Handler2; // Опять сравниваем делегаты с разным содержимым Compare(); } void Compare() { if (del0 == del1) Console.WriteLine("Списки делегатов идентичны"); else Console.WriteLine("Списки делегатов различны"); } } // Запуск class Program { static void Main() { // Настройка консоли Console.Title = MyClass.Title; Console.ForegroundColor = ConsoleColor.White; Console.CursorVisible = false; Console.WindowWidth = 33; Console.WindowHeight = 4; new MyClass();// Исполняем Console.ReadLine(); } } }Листинг 10.15 . Перегруженные операторы 'operator ==' и 'operator !='
Обратите внимание, что для равенства делегатов важен не только состав функций, но и порядок их следования в списке.