Делегаты c#

Делегаты 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# и о том, как их использовать.

На связи был Алексей Гулынин, оставляйте свои комментарии, увидимся в следующих статьях.


Комментарии:

3 комментарии

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *