Делегаты c#
Всем доброго времени суток. На связи Алексей Гулынин. В прошлой статье вы узнали немного о том, как работать с LINQ в C#. В данной статье я бы хотел разобрать тему, посвященную делегатам в C#. Делегат представляет собой объект, который может ссылаться на метод, но это не просто указатель на метод, а множество указателей на метод (фактически коллекция, на последнем примере будет понятно почему это коллекция). Делегат указывает не на произвольный метод, а на метод с определенным набором параметров. Для того, чтобы сделать указатель на какой-нибудь метод, нужно сначала описать тип делегата.
Делегат — это тип (причем ссылочный), а переменная типа делегата внутри себя хранит множество значений, каждое из которых представляет из себя указатель на метод, сигнатура которого совпадает с сигнатурой метода, определенного в этом типе делегата. Тип делегата объявляется с помощью ключевого слова "delegate". Давайте попробуем на примере разобраться как определяется делегат и как его использовать:
// Опеределение типа делегата public delegate int MyMethodHandler(Room room, EventArgs args);
"MyMethodHandler" — это теперь тип.
Делегатам можно не передавать параметры, можно указать произвольное количество параметров, но обычно используют 2 параметра. Первый параметр — это источник (кто вызывает этот делегат), а второй — это объект класса "EventArgs" или наследник класса "EventArgs".
После того, как создан тип делегата, можно создать поле типа этого делегата:
// создание поля public event MyMethodHandler MyMethod;
"Public" означает, что этот делегат будет доступен снаружи класса.
"Event" означает, что вызывать можно только изнутри класса, хоть он и доступен вне (если event опустить, то и вызывать можно вне класса).
Когда "event" стоит, то такое поле называют событием. Подписаться на такое событие можно вне класса, а вызываться оно будет только изнутри класса.
Подписка на событие означает, что берётся указатель на какой-то метод, и добавляется в делегат.
Вывоз делегата означает, что будут вызваны все те методы, указатели на которые сохранены в этом делегате.
Делегат вызывается следующим образом:
if (MyMethod != null) { MyMethod(this,e); }
На "null" проверяют из-за того, что в делегате может не быть ни одного указателя, т.е. никто не подписался на событие.
Как сделать метод и его адрес занести в делегат?
Сначала создаём метод. Назвать его можно любым образом. Важно, чтобы набор параметров (по типу и по порядку, т.е. сигнатура метода), совпадал с набором параметров, определенных в самом типе делегата. Давайте создадим такой метод:
public int squareRoom(Room room, EventArgs args) { return room.length * room.width; }
Подписываемся на событие следующим образом:
room1.MyMethod += squareRoom;
Обращаю внимание, что имя метода пишется без круглых скобок. Если написать круглые скобки, то этот метод будет вызван, а нам нужно только получить адрес и добавить в этого делегата.
Отписываемся от события:
room1.MyMethod -= squareRoom;
Давайте запишем полностью пример с комнатой. Он будет немного надуманным:
using System; using System.Text; using System.IO; using System.Collections.Generic; using System.Linq; namespace TestApplicationForStudy { class Program { // Объявляем тип делегата public delegate int RoomModification(Room room); // Создаём поле типа делегата public static event RoomModification MyRoom; public class Room { public int length; public int width; public Room(int a, int b) { this.length = a; this.width = b; } } public class TestRoom { // Сумма длины и ширины комнаты public int Summa(Room room) { return room.length + room.width; } // Умножение длины и ширины комнаты public int Multiple(Room room) { return room.length * room.width; } } static void Main(string[] args) { TestRoom testRoom = new TestRoom(); MyRoom += testRoom.Summa; if (MyRoom != null) { Console.WriteLine("Сумма = " + MyRoom(new Room(10, 8))); } MyRoom += testRoom.Multiple; if (MyRoom != null) { Console.WriteLine("Умножение = " + MyRoom(new Room(10, 8))); } // Отписываемся от события умножения MyRoom -= testRoom.Multiple; if (MyRoom != null) { // Так как мы отписались от события умножения, в делегате остался только указатель на один метод Сумма // Поэтому он и отработает Console.WriteLine("Умножение = " + MyRoom(new Room(10, 8))); // Умножение = 18 } Console.ReadLine(); } } }
В заключении хочется отметить, что делегаты используются по двум причинам:
- Они поддерживают события
- Они позволяют вызывать методы во время выполнения программы, не зная о них ничего конкретного во время компиляции
В данной статье вы узнали про делегаты в C# и о том, как их использовать.
На связи был Алексей Гулынин, оставляйте свои комментарии, увидимся в следующих статьях.
void int squareRoom(Room room, EventArgs args)
{
return room.length * room.width;
}
Думаю, стоит поменять void на public
Влад, спасибо, вы правы. Поменял.
Пожалуйста
Спасибо за шикарный сайт.
Очень доступно подан материал.