1.18M
Категория: ПрограммированиеПрограммирование

Делегаты

1.

Делегаты

2.

Определение делегата
Делегат — это вид класса, предназначенный для хранения ссылок на методы.
Делегат, как и любой другой класс, можно передать в качестве параметра, а
затем вызвать инкапсулированный в нем метод.
Делегаты используются для поддержки событий, а также как самостоятельная
конструкция языка.
Описание делегата задает сигнатуру методов, которые могут быть вызваны с его
помощью:
[ атрибуты ] [ спецификаторы ] delegate тип имя([ параметры ])
Пример описания делегата:
public delegate void SendMessage (string message);
Базовым классом делегата является класс System.MulticastDelegate

3.

Пример создания делегата
delegate void SendMessage(string message); //1
class Hello
{
public void Display(string message)
{
Console.WriteLine(message);
}
public void SpellItOut(string message)
{
foreach (var ch in message)
{
Console.Write($"{ch} ");
}
}
}
public class Test
{
public void Main()
{
var hello = new Hello();
SendMessage sendMessage = hello.Display;
// sendMessage?.Invoke("Привет");
sendMessage += hello.SpellItOut;
sendMessage("Привет");
//5
Console.WriteLine();
//Удалим из цепочки один из методов
sendMessage -= hello.SpellItOut;
sendMessage("До свидания");
}
}
//2
//3
//4
//6
//7

4.

Синтаксис работы с делегатами
button1.Click += new EventHandler(button1_Click);
button1.Click += button1_Click;
button1.Click += (sender, eventArgs) => { };
void button1_Click(Object sender, EventArgs e)
{
}

5.

internal delegate void Feedback(Int32 value);
internal class Feedback : System.MulticastDelegate {
// Конструктор
public Feedback(Object object, IntPtr method);
// Метод, прототип которого задан в исходном тексте
public virtual void Invoke(Int32 value);
// ...
}

6.

Безопасность в отношении потоков
private delegate void SendNewEmail(string message);
private SendNewEmail _sendNewEmail;
//Вариант 1
public void SendEmail(string message)
{
if (_sendNewEmail != null) _sendNewEmail(message);
}
//Вариант 2
public void SendEmail(string message)
{
var temp = _sendNewEmail;
if (temp != null) _sendNewEmail(message);
}
//Вариант 3
public void SendEmail(string message)
{
_sendNewEmail?.Invoke(message);
}

7.

Использование делегатов

Делегаты применяются в основном для следующих целей:



получения возможности определять вызываемый метод не при компиляции,
а динамически во время выполнения программы;
обеспечения связи между объектами по типу «источник — наблюдатель»;
создания универсальных методов, в которые можно передавать другие
методы (поддержки механизма обратных вызовов).

8.

Паттерн издатель/подписчик
delegate void BankAccountHandler(decimal sum);
class BankAccount
{
public BankAccountHandler BankAccountHandler;
public void Add(decimal sum)
{
BankAccountHandler?.Invoke(sum);
}
}
class Client
{
private readonly string _name;
private readonly BankAccount _bankAccount;
public Client(string name, BankAccount bankAccount)
{
_name = name;
_bankAccount = bankAccount;
bankAccount.BankAccountHandler = AccountSumChanged;
}
private void AccountSumChanged(decimal sum)
{
Console.WriteLine($"The client's account has changed. Sum: {sum}");
}
}
public class PubSubTest
{
public void Main()
{
var bankAccount = new BankAccount();
var client = new Client("Alex", bankAccount);
bankAccount.Add(45);
}
}

9.

Операции
Делегаты можно сравнивать на равенство и неравенство. Два делегата равны,
если они оба не содержат ссылок на методы или если они содержат ссылки на
одни и те же методы в одном и том же порядке.
С делегатами одного типа можно выполнять операции простого и сложного
присваивания.
Делегат, как и строка string, является неизменяемым (immutable) типом
данных, поэтому при любом изменении создается новый экземпляр, а старый
впоследствии удаляется сборщиком мусора.
● Использование делегата имеет тот же синтаксис, что и вызов метода. Если
делегат хранит ссылки на несколько методов, они вызываются
последовательно в том порядке, в котором были добавлены в делегат.

10.

Встроенные делегаты
public delegate void Action(); // Этот делегат не обобщенный
public delegate void Action<T>(T obj);
public delegate void Action<T1, T2>(T1 arg1, T2 arg2);
public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);
...
public delegate void Action<T1, ..., T16>(T1 arg1, ..., T16 arg16);
public delegate TResult Func<TResult>();
public delegate TResult Func<T, TResult>(T arg);
public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
public delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3);
...
public delegate TResult Func<T1,..., T16, TResult>(T1 arg1, ..., T16 arg16);
delegate bool Predicate<in T>(T obj);

11.

События

12.

Определение события
Событие — элемент класса, позволяющий ему посылать другим объектам
(наблюдателям) уведомления об изменении своего состояния.

13.

Механизм событий
описание делегата, задающего сигнатуру обработчиков событий;
описание события;
описание метода (методов), инициирующих событие.
Синтаксис события:
[ атрибуты ] [ спецификаторы ] event тип имя

14.

Пример
public class FallsIllEventArgs : EventArgs
{
public string Address;
}
public class Person
{
public void CatchACold()
{
FallsIll?.Invoke(this,
new FallsIllEventArgs { Address = "123 London Road" });
}
public event EventHandler<FallsIllEventArgs> FallsIll;
}
public class Demo
{
static void Main()
{
var person = new Person();
person.FallsIll += CallDoctor;
person.CatchACold();
}
private static void CallDoctor(object sender, FallsIllEventArgs eventArgs)
{
Console.WriteLine($"A doctor has been called to {eventArgs.Address}");
}
}

15.

Литература
Изучаем C#. Автор: Эндрю Стиллмен, Дженнифер Грин
"CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на
языке C#". Автор: Рихтер
https://ulearn.me/
Курс по C# от Veeam Software
English     Русский Правила