Содержание
В предыдущей части мы разобрались, в общих чертах, что из себя представляют делегаты в C# и научились их вызывать. При этом за кадром остался вопрос — какую практическую пользу несут делегаты? Как они используются в реальных проектах? И сегодня мы рассмотрим один из возможных примеров использования делегатов в C#. Одно из преимуществ делегата состоит в том, что,используя его мы можем делегировать выполнение кода абсолютно любому методу с той же сигнатурой, что и у делегата.
Использование делегатов в C# на примере своего класса
Мы уже знаем, что такое класс и как его создавать, поэтому наглядное применение делегатов в C# наиболее выгодно продемонстрировать именно при использовании их в классах. Допустим, мы пишем приложение для работы со списком сотрудников организации. Для этого у нас в программе определен класс Person
public class Person { public string Name { get; set; } public string Surname { get; set; } public string Department { get; private set; } public byte Age { get; set; } public void ChangeDepartmnet(string newDepartment) { Department = newDepartment; } }
У класса сотрудника определены свойства: имя, фамилия и отдел в котором он работает. При этом, свойство Department
у нас доступно извне только для чтения и чтобы изменить название отдела в котором работает сотрудник необходимо вызвать метод ChangeDepartmnet()
. Теперь попробуем ответить на такой вопрос: что нам (как пользователям этого класса) потребуется сделать, если мы захотим изменить логику метода ChangeDepartmnet()
, например, вывести в консоль строку с информацией о том, что у сотрудника изменился отдел? Правильно — мы перепишем тело нашего метода. А что, если этот класс будет находится в какой-нибудь библиотеке классов и мы не имеем доступа к исходному коду этого метода? И вот здесь-то и раскрывается преимущество использования делегата в C# — мы можем делегировать выполнение необходимых нам действий другому методу. Перепишем наш класс следующим образом:
public class Person { public delegate void PrintString(string str); //объявили делегат PrintString print; //объявили переменную делегата public string Name { get; set; } public string Surname { get; set; } public string Department { get; private set; } public byte Age { get; set; } public void ChangeDepartmnet(string newDepartment) { Department = newDepartment; print?.Invoke($"Отдел работы сотрудника {Name} {Surname} изменен на {newDepartment}"); } public void Register(PrintString printString) { print += printString; } public void Unregister(PrintString printString) { print -= printString; } }
Здесь мы, во-первых, объявили делегат PrintString
:
public delegate void PrintString(string str); //объявили делегат
во-вторых, объявили переменную типа делегата:
PrintString print; //объявили переменную делегата
в-третьих, так как давать прямой доступ к переменным класса извне не рекомендуется, то мы создали два метода — для добавления метода к делегату (Register
) и снятия метода (Unregister
).
в-четвертых, переписали метод ChangeDepartmnet
в котором производим вызов делегата в том случае, если он не равен null, то есть переменная делегата ссылается хотя бы на один метод.
Теперь протестируем наш класс:
class Program { //использование делегатов static void Main(string[] args) { Person person = new Person { Name = "Вася", Surname = "Пупкин" }; person.ChangeDepartmnet("Курьерский"); person.Register(Show); person.ChangeDepartmnet("Общий"); } public static void Show(string message) { Console.WriteLine(message); } }
Здесь мы добавили метод Show
в делегат после первого вызова метода ChangeDepartmnet
. Следовательно, в консоли мы увидим только такую строку:
Последовательный вызов методов делегата
Опять же, никто нам не запрещает регистрировать несколько методов для делегата, объявленного в нашем классе Person
и эти методы последовательно будут вызываться. Перепишем код нашей программы следующим образом:
class Program { //использование делегатов static void Main(string[] args) { Person person = new Person { Name = "Вася", Surname = "Пупкин" }; person.Register(Show); person.Register(ShowRed); person.ChangeDepartmnet("Общий"); } public static void Show(string message) { Console.ResetColor(); Console.WriteLine(message); } public static void ShowRed(string message) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(message); } }
Теперь переменная делегата содержит ссылки на два метода — Show
и ShowRed
. Таким образом, в консоль выведется две строки — одна белого цвета, а вторая — красного. При этом, обратите, внимание, что исходный код класса Person
мы не изменяли.
Итого
Таким образом, использование делегатов в классах C# позволяет делегировать выполнение какого-либо кода другим методам, даже не принадлежащим классу. В качестве примера, мы рассмотрели свой класс Person который содержит переменную делегата, выводящего в консоль какую-либо информацию. Изученной на данный момент информации нам теперь достаточно, чтобы прейти к следующему интересному моменту использования делегатов — созданию и использованию событий в C#.