Разделы презентаций


Делегаты

Содержание

ДелегатыДелегат – это так называемый “безопасный указатель на функцию”, делегаты C# могут вызывать более одной функции (при совместном комбинировании двух делегатов результатом будет делегат, который вызывает их обоих). “безопасность” – в

Слайды и текст этой презентации

Слайд 1Делегаты. События

Делегаты. События

Слайд 2Делегаты
Делегат – это так называемый “безопасный указатель на функцию”,
делегаты

C# могут вызывать более одной функции (при совместном комбинировании двух

делегатов результатом будет делегат, который вызывает их обоих).
“безопасность” – в С++ указатель на функцию – это фактически просто адрес, делегат позволяет проверять количество передаваемых параметров, возвращаемое значение и т.д.
Многие конструкции C# - это классы, так и делегат - это класс отнаследованный от базового класса System.MulticastDelegate.
Делегат можно объявлять как в классе, так и просто в пространстве имен.
ДелегатыДелегат – это так называемый “безопасный указатель на функцию”, делегаты C# могут вызывать более одной функции (при

Слайд 3Создание делегата
объявляется сам делегат как тип и сразу же задается

прототип функций, которые в будущем могут адресоваться экземплярами этого типа.
объявляется

ссылка типа делегата, которая будет указывать на коллекцию экземпляров делегата.
создаются сами объекты делегата, каждый из которых адресует одну функцию, и комбинируются в коллекцию, на которую указывает объявленная ссылка.

Коллекция - собой список адресуемых делегатом функций и поддерживается операциями += и -= или статическими методами  Delegate.Combine() и Delegate.Remove()
Экземпляр делегата способен вызывать эти методы либо по одному, либо сразу весь список.

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

Слайд 4Одноадресная работа делегатов
Во время выполнения программы один и тот же

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

заменой метода, на который ссылается делегат (главное достоинство делегата, что адресуемый им метод определяется не на этапе компиляции, а в период выполнения). Заменяя в делегате адресуемые функции мы обеспечим их полиморфный вызов.

Область видимости делегата можно регулировать точно так же, как и область видимости любого другого типа в приложении.

Одноадресная работа делегатовВо время выполнения программы один и тот же делегат можно использовать для вызова разных методов

Слайд 5class DelegateTest {

// Объявляем функции с сигнатурой делегатов

public void Show1() {
Console.WriteLine("Вызов: void Show1()"); }
// Объявляем функции с сигнатурой делегатов
public void Show2() {
Console.WriteLine("Вызов: void Show2()"); }
// Объявляем функции с сигнатурой делегатов
public int Draw1(string str1) {
Console.WriteLine("Вызов: {0}", str1); return 1; }
// Объявляем функции с сигнатурой делегатов
public int Draw2(string str2) {
Console.WriteLine("Вызов: {0}", str2); return 2; }
// Объявляем статическую функцию
public static int Print(string str) {
Console.WriteLine("Вызов: {0}", str); return 0; } }
// Объявляем делегат в пространстве имен
delegate void TypeShow();
// Вызывающая сторона
class MyClass {
// Объявляем делегат в классе
delegate int TypeDraw(string str);
public MyClass() {
// Создаем экземпляр класса с методами
DelegateTest delegateTest = new DelegateTest();
// Объявляем ссылки на объекты делегатов
TypeShow typeShow;
TypeDraw typeDraw;
// Создаем объекты делегатов
typeShow = new TypeShow(delegateTest.Show1);
typeDraw = new TypeDraw(delegateTest.Draw1);
// Вызываем методы посредством делегатов
typeShow();
typeDraw("int Draw1(string str1)");
// Адресуемся к другим методам с той же сигнатурой
typeShow = new TypeShow(delegateTest.Show2);
typeDraw = new TypeDraw(delegateTest.Draw2);
// Вызываем другие методы посредством делегатов
typeShow();
typeDraw("int Draw2(string str2)");
// Вызываем статический метод
// посредством подходящего делегата
typeDraw = new TypeDraw(DelegateTest.Print);
typeDraw("static int Print(string str)"); } }

// Запуск
class Program {
static void Main() {
// Настройка консоли
Console.Title = "Применение делегатов";
new MyClass(); // Чтобы сработал конструктор
} }

class DelegateTest    {      // Объявляем функции с сигнатурой делегатов

Слайд 6
Делегат может адресовать как методы объекта (экземпляра класса), так и

статические методы.
Надо, чтобы заголовки объявления делегата и объявления метода

совпадали как по типу возвращаемого значения, так и по сигнатуре.
Делегат может адресовать как методы объекта (экземпляра класса), так и статические методы. Надо, чтобы заголовки объявления делегата

Слайд 7Многоадресная работа делегатов

Многоадресная работа делегатов

Слайд 8// Для методов, имеющих одинаковую сигнатуру и не возвращающих значение

(только с void) с помощью делегата можно организовать сразу цепочку вызовов
class

MultiTest {
// Статическое поле
static int x = 1;
// Объявляем функции с одинаковой сигнатурой
public void Handler1(string name) {
Console.WriteLine(name + x++); }
public void Handler2(string name) {
Console.WriteLine(name + x++); }
public void Handler3(string name) {
Console.WriteLine(name + x++); } }
// Вызывающая сторона
class MyClass {
// Объявляем делегат в классе
delegate void TypeHandler(string text);
public MyClass() {
// Создаем экземпляр класса с методами
MultiTest obj = new MultiTest();
// Создаем объект-делегат и заполняем адресами
TypeHandler Handler = new TypeHandler(obj.Handler1);
Handler += new TypeHandler(obj.Handler2);
Handler += obj.Handler3; // Упрощенный синтаксис
// Вызываем цепочку методов
Handler("Вызов: Handler"); } }

// Запуск
class Program {
static void Main() {
// Настройка консоли
Console.Title = "Многоадресные делегаты";
new MyClass(); // Чтобы сработал конструктор
} }
// Для методов, имеющих одинаковую сигнатуру и не возвращающих значение (только с void) с помощью делегата можно организовать

Слайд 9Делегаты являются экземплярами типа System.MulticastDelegate, который в свою очередь наследует абстрактный

класс System.Delegate.
Экземпляр типа MulticastDelegate может хранить в себе одну или сразу несколько

ссылок на методы. В любом случае мы не можем явно объявлять делегат с помощью типа MulticastDelegate.
Это делается с помощью ключевого слова delegate, но неявно порождается объект класса MulticastDelegate.
структура примера через панель Class View.
Делегаты являются экземплярами типа System.MulticastDelegate, который в свою очередь наследует абстрактный класс System.Delegate. Экземпляр типа MulticastDelegate может хранить в себе одну

Слайд 10Пустые делегаты
Делегат существует как объект до тех пор, пока его

список с адресуемыми функциями содержит хотя-бы одну функцию.
Как только

список делегата становится пустым, то он превращается в обычную ссылочную переменную с нулевой адресацией.
Т.к. мы можем не только пополнять список, но и удалять из него некоторые функции, то необходимо следить за тем, чтобы список делегата не оказался пустым, иначе при попытке вызова такого списка будет выброшено исключение.
Пустые делегатыДелегат существует как объект до тех пор, пока его список с адресуемыми функциями содержит хотя-бы одну

Слайд 11class MultiTest {
// Объявляем функции

одного прототипа
public void Handler1()

{
Console.WriteLine("Исполняется Handler1"); }
public void Handler2() {
Console.WriteLine("Исполняется Handler2"); }
public void Handler3() {
Console.WriteLine("Исполняется Handler3"); } }

// Вызывающая сторона
class MyClass {
// Для заголовка консольного окна
public static string Title = "Пустые делегаты“;
// Объявляем делегат как член класса
delegate void MyDelegate();
public MyClass() {
// Создаем экземпляр класса с методами
MultiTest obj = new MultiTest();
// Создаем объект-делегат и заполняем ссылками на функции
// Инициализируем первой ссылкой
MyDelegate del = new MyDelegate(obj.Handler1);
// Добавляем другие ссылки
del += obj.Handler2;
del += obj.Handler3;
// Вызываем цепочку методов
del();
Console.WriteLine();
// Извлекаем метод и опять вызываем цепочку методов
del -= obj.Handler1;
del();
Console.WriteLine();
// Извлекаем метод и опять вызываем цепочку методов
del = (MyDelegate)Delegate.Remove(del, new MyDelegate(obj.Handler2));
del();
Console.WriteLine();
// Извлекаем последний метод и пытаемся адресоваться к пустому делегату
del -= obj.Handler3;
//del(); // Будет выброшено исключение, нужно проверять!!!
if (del != null) {
del(); // Так все нормально!
}
else
Console.WriteLine("Список делегата исчерпан!"); } }

// Запуск
class Program {
static void Main() {
// Настройка консоли
Console.Title = MyClass.Title;
new MyClass(); // Исполняем
} }
class MultiTest  {    // Объявляем функции одного прототипа    public void

Слайд 12
если делегат имеет пустой список, т.е. не ссылается ни на

одну функцию, то представляющая его ссылка имеет нулевой адрес

если делегат имеет пустой список, т.е. не ссылается ни на одну функцию, то представляющая его ссылка имеет

Слайд 13Некоторые члены типа MulticastDelegate
Тип MulticastDelegate сам имеет несколько своих собственных членов, но

большую часть он наследует от абстрактного класса Delegate.
Члены типа MulticastDelegate содержат все

необходимые сервисы по управлению делегатами. Некоторые из этих членов экземплярные, а некоторые - статические.

Некоторые члены типа MulticastDelegateТип MulticastDelegate сам имеет несколько своих собственных членов, но большую часть он наследует от абстрактного класса Delegate.

Слайд 14Некоторые члены типа MulticastDelegate, унаследованные от Delegate

Некоторые члены типа MulticastDelegate, унаследованные от Delegate

Слайд 15//Применение свойства Method
class MultiTest {
//

Статическое поле
static int x = 1;

// Объявляем функции с одинаковой сигнатурой
public void Handler1() {
Console.WriteLine("Исполняется Handler1"); }
public void Handler2() {
Console.WriteLine("Исполняется Handler2"); }
public void Handler3() {
Console.WriteLine("Исполняется Handler3"); }
}

// Вызывающая сторона
class MyClass {
public static string Title = "Свойство Method“;
// Объявляем делегат как член класса
delegate void MyDelegate();
public MyClass() {
// Создаем экземпляр класса с методами
MultiTest obj = new MultiTest();
// Создаем объект-делегат и заполняем ссылками на функции
// Инициализируем первой ссылкой
MyDelegate del = new MyDelegate(obj.Handler1);
// Добавляем другие ссылки
del += obj.Handler2;
del += obj.Handler3;
// Вызываем цепочку методов
del();
Console.WriteLine();
del.Method.Invoke(obj, null); // Вызываем последний метод
Console.WriteLine("\nПрототип последнего метода:\n{0}",
del.Method.ToString());
Console.WriteLine("\nИмена адресуемых методов:");
Delegate[] listMethods = del.GetInvocationList();
for (int i = 0; i < listMethods.Length; i++)
Console.WriteLine("{0}", listMethods[i].Method.Name); } }

// Запуск
class Program {
static void Main() {
// Настройка консоли
Console.Title = MyClass.Title;
new MyClass(); // Исполняем
} }
//Применение свойства Methodclass MultiTest  {    // Статическое поле    static int

Слайд 16//Свойство Target - свойство возвращает объект, связанный с адресуемым делегатом

методом
class MultiTest {
// Объявляем функции

с одинаковой сигнатурой
public void Handler1() {
Console.WriteLine("Исполняется Handler1"); }
public void Handler2() {
Console.WriteLine("Исполняется Handler2"); }
public void Handler3() {
Console.WriteLine("Исполняется Handler3"); } }
// Вызывающая сторона
class MyClass {
public static string Title = "Применение свойства Target делегата";
// Объявляем делегат как член класса
delegate void MyDelegate();
public MyClass() {
// Создаем экземпляр класса с методами
MultiTest obj = new MultiTest();
// Создаем объект-делегат и заполняем ссылками на функции
// Инициализируем первой ссылкой
MyDelegate del = new MyDelegate(obj.Handler1);
// Добавляем другие ссылки
del += obj.Handler2; del += obj.Handler3;

// Вызываем цепочку методов
Console.WriteLine("Многоадресный вызов через делегат");
del();
Console.WriteLine();
// Возвращает объект, с которым связан
// последний адресуемый метод
Console.WriteLine("Тип объекта: {0}",
del.Target.GetType().ToString());
Console.WriteLine();
// Повышаем полномочия извлеченной из Target ссылки
// на объект и повторно адресуемся напрямую
Console.WriteLine("Вызов через свойство Target делегата");
((MultiTest)del.Target).Handler1();
((MultiTest)del.Target).Handler2();
((MultiTest)del.Target).Handler3();
Console.WriteLine();
// Адресуемся напрямую без делегата
Console.WriteLine("Вызов через объект напрямую");
obj.Handler1(); obj.Handler2();
obj.Handler3(); } }



//Свойство Target - свойство возвращает объект, связанный с адресуемым делегатом методомclass MultiTest  {

Слайд 17
// Запуск
class Program {

static void Main() {

// Настройка консоли
Console.Title = MyClass.Title;
new MyClass(); // Исполняем
} }

// Запуск  class Program  {    static void Main()    {

Слайд 18Методы DynamicInvoke() и GetInvocationList()
позволяет вызывать отдельные члены, адресуемые списком объекта-делегата,

и задавать требуемые аргументы.
Если член списка не имеет аргументов,

то в качестве параметра метода используется null, иначе - массив параметров адресуемого члена.
объявление ссылки на объект-делегат прописывает только прототип методов, которые корректно может адресовать эта ссылка.
делегат как объект создается при заполнении списка адресуемыми функциями. Но при формировании списка в него добавляются только имена методов. Это приемлемо, если вызываются функции с пустой сигнатурой.

Методы DynamicInvoke() и GetInvocationList()позволяет вызывать отдельные члены, адресуемые списком объекта-делегата, и задавать требуемые аргументы. Если член списка

Слайд 19class 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;
new MyClass(); // Исполняем
} }

все зарегистрированные в делегате методы стороннего класса получают, при вызове их с помощью делегата, одинаковую входную информацию

class ShowPerson  {    // Объявляем функцию с аргументами    public static

Слайд 20если с помощью делегата нужно адресовать методы, имеющие разные значения

параметров используется
public object DynamicInvoke(params object[ ] args)
с помощью метода DynamicInvoke() можно

решить проблему надежности кода при адресации вызовов методов посредством делегата.
Если любой из цепочки метод при традиционном вызове может дать сбой, то в результате система выдаст исключение и прервет вызовы остальных методов списка. Исключение мы можем обработать, но только для списка в целом, если не будем контролировать индивидуально каждый член списка делегата.
Эти проблемы решает метод DynamicInvoke() совместно с GetInvocationList()


если с помощью делегата нужно адресовать методы, имеющие разные значения параметров используетсяpublic object DynamicInvoke(params object[ ] args)с

Слайд 21class 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 ShowPerson  {    // Функция с аргументами    public static void

Слайд 22
// Запуск
class Program
{

static void Main()
{

// Настройка консоли
Console.Title = MyClass.Title;
new MyClass(); // Исполняем
}
}
// Запуск  class Program  {    static void Main()

Слайд 23Перегруженные операторы 'operator ==' и 'operator !='
Эти операторы позволяют подтвердить

или опровергнуть абсолютную идентичность списков функций сравниваемых делегатов.

Перегруженные операторы 'operator ==' и 'operator !='Эти операторы позволяют подтвердить или опровергнуть абсолютную идентичность списков функций сравниваемых

Слайд 24class 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;
new MyClass(); // Исполняем
} }

Слайд 45class MyClass {// Получатель сообщения
//

Конструктор
public MyClass()

{
// Создаем объект, имеющий событие
SourceEvent obj = new SourceEvent();
// Подписываемся на обработчики события
obj.Event += new EventHandler(Handler1);
obj.Event += new EventHandler(Handler2);
// Вызываем симулятор возникновения события
obj.SimulateEvent(); }
void Handler1(object sender, EventArgs e) {
// Хотим извлечь информацию из толстого объекта,
// значит нужно повысить полномочия тонкой ссылки
MyEventArgs args = (MyEventArgs)e;
String message = args.Message;
Console.WriteLine("(Handler1) Получена информация:\n" + message);
Console.WriteLine(); }
void Handler2(object sender, EventArgs e) {
Console.WriteLine("(Handler2) Событие из объекта {0}\n" + "Передан объект-аргумент {1}”, sender.GetType().Name, e.GetType().Name);
} }
// Запуск
class Program {
static void Main() {
// Настройка консоли
Console.Title = "Применение делегата EventHandler";
new MyClass(); // Исполняем
} }
class MyClass  {// Получатель сообщения    // Конструктор    public MyClass()

Обратная связь

Если не удалось найти и скачать доклад-презентацию, Вы можете заказать его на нашем сайте. Мы постараемся найти нужный Вам материал и отправим по электронной почте. Не стесняйтесь обращаться к нам, если у вас возникли вопросы или пожелания:

Email: Нажмите что бы посмотреть 

Что такое TheSlide.ru?

Это сайт презентации, докладов, проектов в PowerPoint. Здесь удобно  хранить и делиться своими презентациями с другими пользователями.


Для правообладателей

Яндекс.Метрика