|
Прошел курс. Получил код 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 !='
Обратите внимание, что для равенства делегатов важен не только состав функций, но и порядок их следования в списке.


