Создание экземпляров и вызов типов делегатов

Завершено

Типы делегатов реализуются с помощью следующего процесса:

  1. Объявите делегат: задайте тип делегата с указанной сигнатурой, которая включает тип возвращаемого значения и параметры.
  2. Создайте экземпляр делегата: создайте экземпляр типа делегата, указав метод для вызова.
  3. Вызов делегата: вызовите делегат, передавая необходимые аргументы.

После объявления именованного делегата можно создать экземпляры этого типа делегата и использовать их для вызова методов, которые соответствуют сигнатуре делегата. Каждый экземпляр делегата может указывать на другой метод, что позволяет выполнять вызов гибких и динамических методов. Кроме того, делегаты можно объединить для создания мультикаст-делегатов, которые позволяют вызывать несколько методов в одном вызове.

Когда делегат вызывается, он вызывает методы, на которые указывает, передавая аргументы, указанные в сигнатуре делегата.

Инициализация и вызов делегатов

Делегаты можно создавать путем использования именованных методов, конвертации групп методов, анонимных методов или лямбда-выражений. Выбор метода инстанцирования зависит от конкретного варианта использования и требуемого уровня удобочитаемости и удобства поддержки.

Инстанцирование делегатов с именованными методами

Именованные методы определяются с определенным именем и могут использоваться повторно. Использование именованных методов полезно, когда вы хотите создать экземпляр делегата, который указывает на конкретный метод. Именованные методы обычно определяются в классе или структуре и могут быть статическими или экземплярными методами.


public delegate void Notify(string message);

public class Program
{
    public static void Main()
    {
        // Create an instance of the delegate using a named method
        Notify notify = new Notify(NotificationService.SendNotification);

        // Invoke the delegate
        notify("Hello, World!");
    }
}

public static class NotificationService
{
    // Method that matches the delegate's signature
    public static void SendNotification(string message)
    {
        Console.WriteLine("Notification sent: " + message);
    }
}

В этом примере показано, как создать тип Notify делегата, который принимает строковый параметр и возвращает void. Метод SendNotification соответствует сигнатуре делегата, что позволяет присвоить его экземпляру делегата. Когда вызывается делегат, он вызывает метод SendNotification с предоставленным сообщением.

Создание делегатов с помощью преобразования групп методов

Преобразование групп методов — это краткий способ создания экземпляра делегата путем прямого ссылки на метод без явного создания экземпляра делегата. Использование преобразования групп методов полезно при создании экземпляра делегата, указывающего на конкретный метод без необходимости явного конструктора делегата. Преобразование группы методов позволяет назначать метод напрямую типу делегата, исключая необходимость явного создания экземпляра делегата. Эта возможность полезна, если сигнатура метода соответствует подписи делегата, так как она позволяет более чистому и более краткому коду.


public delegate void Notify(string message);

public class Program
{
    public static void Main()
    {
        // Create an instance of the delegate using a method group conversion for a named method
        Notify notifyMethodGroup = NotificationService.SendNotification;

        // Invoke the delegate
        notifyMethodGroup("Hello from Method Group!");

    }
}

public static class NotificationService
{
    // Method that matches the delegate's signature
    public static void SendNotification(string message)
    {
        Console.WriteLine("Notification sent: " + message);
    }
}


В этом примере показано, как создать экземпляр делегата с помощью преобразования группы методов. Метод SendNotification назначается непосредственно экземпляру notifyMethodGroupделегата, что позволяет вызывать его с помощью сообщения. Когда вызывается делегат, он вызывает метод SendNotification с предоставленным сообщением.

Создание экземпляров делегатов с помощью анонимных методов

Анонимные методы позволяют определять встроенный метод без явного именования. Эта возможность полезна для краткосрочных операций или при необходимости определения поведения непосредственно в точке использования. Анонимные методы можно использовать для создания объектов делегатов без определения отдельного метода. Использование анонимных методов позволяет получить более краткий код и улучшить удобочитаемость в определенных сценариях.


public delegate void Notify(string message);

public class Program
{
    public static void Main()
    {
        // Create an instance of the delegate using an anonymous method
        Notify notifyAnonymous = delegate (string message) { Console.WriteLine("Anonymous notification: " + message); };

        // Invoke the delegate
        notifyAnonymous("Hello from Anonymous Method!");

    }
}

В этом примере показано, как создать экземпляр делегата с помощью анонимного метода. Анонимный метод delegate (string message) { Console.WriteLine("Anonymous notification: " + message); } определяет поведение встроенного делегата, что позволяет вызывать его с помощью сообщения. При вызове делегата выполняется код, определенный в анонимном методе.

Создание экземпляров делегатов с лямбда-выражениями

Лямбда-выражения — это краткий способ определения анонимных методов. Они позволяют создавать экземпляры делегатов без явного определения метода. Эта возможность полезна для краткосрочных операций или при необходимости определения поведения непосредственно в точке использования.


public delegate void Notify(string message);

public class Program
{
    public static void Main()
    {
        // Create an instance of the delegate using a lambda expression
        Notify notifyLambda = (message) => Console.WriteLine("Lambda notification: " + message);

        // Invoke the delegate
        notifyLambda("Hello from Lambda!");
    }
}

В этом примере показано, как создать экземпляр делегата с помощью лямбда-выражения. Лямбда-выражение (message) => Console.WriteLine("Lambda notification: " + message) определяет поведение встроенного делегата, что позволяет вызывать его с помощью сообщения. При вызове делегата выполняется код, определенный в лямбда-выражении.

Вызов одноадресных и многоадресных делегатов

Делегаты могут вызываться как обычные методы. Когда делегат вызывается, он вызывает методы, на которые указывает, передавая аргументы, указанные в сигнатуре делегата. Вызов делегата аналогичен вызову метода напрямую.

Делегаты можно объединять для создания многоадресных делегатов, которые позволяют вызывать несколько методов в одном вызове. Возможность многоадресной рассылки полезна при выполнении нескольких действий, таких как уведомление нескольких подписчиков событий или выполнение нескольких методов в определенном порядке.

Несколько объектов могут быть назначены одному экземпляру делегата с помощью оператора +. Делегат многоадресной рассылки содержит список назначенных делегатов. Когда вызывается многоадресный делегат, он последовательно вызывает делегатов из списка. Можно объединить только делегатов одного типа.

Оператор - можно использовать для удаления делегата компонента из мультиадресного делегата.

В следующем примере показано, как объединить делегатов с помощью + оператора и удалить делегат с помощью - оператора:


using System;

namespace DelegateExamples;

// Define a custom delegate that has a string parameter and returns void.
delegate void CustomCallback(string s);

class TestClass
{
    // Define two methods that have the same signature as CustomCallback.
    static void Hello(string s)
    {
        Console.WriteLine($"  Hello, {s}!");
    }

    static void Goodbye(string s)
    {
        Console.WriteLine($"  Goodbye, {s}!");
    }

    static void Main()
    {
        // Declare instances of the custom delegate.
        CustomCallback hiDel, byeDel, multiDel, multiMinusHiDel;

        // Initialize the delegate object hiDel that references the
        // method Hello.
        hiDel = Hello;

        // Initialize the delegate object byeDel that references the
        // method Goodbye.
        byeDel = Goodbye;

        // The two delegates, hiDel and byeDel, are combined to
        // form multiDel.
        multiDel = hiDel + byeDel;

        // Remove hiDel from the multicast delegate, leaving byeDel,
        // which calls only the method Goodbye.
        multiMinusHiDel = (multiDel - hiDel)!;

        Console.WriteLine("Invoking delegate hiDel:");
        hiDel("Elize Harmsen");

        Console.WriteLine("Invoking delegate byeDel:");
        byeDel("Mattia Trentini");

        Console.WriteLine("Invoking delegate multiDel:");
        multiDel("Peter Zammit");

        Console.WriteLine("Invoking delegate multiMinusHiDel:");
        multiMinusHiDel("Lennart Kangur");
    }
}

/* Output:
Invoking delegate hiDel:
  Hello, Elize Harmsen!
Invoking delegate byeDel:
  Goodbye, Mattia Trentini!
Invoking delegate multiDel:
  Hello, Peter Zammit!
  Goodbye, Peter Zammit!
Invoking delegate multiMinusHiDel:
  Goodbye, Lennart Kangur!
*/

В этом примере показано, как создать многоадресный делегат путем объединения двух делегатов (hiDel и byeDel) с помощью оператора +. Объединенный делегат (multiDel) вызывает оба метода при вызове. Оператор - используется для удаления одного из делегатов из многоадресного делегата, оставляя только другой делегат для вызова.

Выходные данные показывают результаты вызова каждого делегата, демонстрируя, как работает многоадресный делегат.

Распространенные сценарии использования делегатов

Делегаты являются универсальными и могут использоваться в различных сценариях для повышения гибкости кода и удобства обслуживания. Они полезны в ситуациях, когда необходимо передать методы в качестве параметров, реализовать механизмы обратного вызова или создать обработчики событий.

Ниже приведены некоторые распространенные сценарии, в которых используются делегаты:

  • Сортировка и фильтрация. Делегаты можно использовать для передачи функций сравнения методам сортировки и фильтрации. Этот процесс позволяет динамически указывать критерии сортировки или фильтрации коллекции объектов. Например, сортировка списка клиентов банка по разным критериям, таким как имя, баланс счета или идентификатор клиента.

  • Методы обратного вызова: делегаты часто используются для реализации методов обратного вызова. Эта возможность полезна в сценариях, когда метод должен вызывать другой метод после завершения определенной операции. Например, можно использовать делегат для уведомления о завершении задачи обработки данных.

  • Асинхронное программирование: делегаты используются для вызова асинхронных методов. Эта возможность полезна для выполнения задач, которые могут занять много времени, например операции ввода-вывода файлов или сетевые запросы. Делегаты позволяют указать метод, который будет вызываться после завершения асинхронной операции.

  • Обработка событий. Делегаты являются основой для событий в C#. Они позволяют определить обработчики событий, которые могут вызываться при возникновении события. Например, в банковском приложении можно использовать делегаты для уведомления клиентов о завершении транзакции.

  • Реализация шаблонов проектирования. Делегаты используются в различных шаблонах проектирования, таких как шаблон стратегии, где можно динамически изменять поведение метода во время выполнения, передав различные реализации делегатов.

Замечание

Сценарий обработки событий рассматривается в отдельном модуле вместе с введением в использование событий в приложениях C#.

Ключевые моменты

  • Экземпляры делегатов можно создавать с помощью именованных методов, преобразования групп методов, анонимных методов или лямбда-выражений.
  • Делегаты могут вызываться как обычные методы, а также объединяться для создания мультикаст-делегатов.
  • Делегаты используются в различных сценариях, включая сортировку и фильтрацию, методы обратного вызова, асинхронное программирование, обработку событий и реализацию шаблонов проектирования.