Содержание
В предыдущей части мы разобрались, в общих чертах, что из себя представляют делегаты в 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#.