C# Event

События C# (Event) — это члены, используемые для отправки подписчикам уведомлений о конкретных событиях. События обычно используются для реализации шаблона наблюдателя, который позволяет объекту уведомлять другие объекты об изменениях состояния, не зная деталей этих объектов.

СобытиеВ основном это действие пользователя, например нажатия клавиш, щелчки, движения мыши и т. д., или некоторая подсказка, например уведомления, созданные системой. Приложения должны реагировать на события при их возникновении. Например, прерывания.

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

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

  • Объявите делегат: Определите тип делегата, который будет использовать событие. Делегат — это сигнатура функции.
  • Объявление события: ИспользуйтеeventКлючевое слово объявляет событие.
  • Запуск события: Вызовите событие в подходящий момент, чтобы уведомить всех подписчиков.
  • Подписка на события и отписка от событий: Другие классы могут+=и-=использовать операторы для подписки на события и отписки от событий.

Использование делегатов через события

События объявляются и инициируются в классе и связываются с обработчиками событий через делегаты в том же классе или других классах. Класс, содержащий событие, используется для публикации события. Это называетсяиздательскими (publisher)классами. Другие классы, которые принимают это событие, называютсяПодписчикКласс. Использование событийпубликация-подписка (издатель-подписчик)модель.

Издатель (publisher)— это объект, который содержит определения событий и делегатов. Связь между событием и делегатом также определяется в этом объекте. Объект класса издателя вызывает это событие и уведомляет другие объекты.

Подписчик— это объект, который принимает событие и предоставляет обработчик событий. Делегат в классе издателя вызывает методы (обработчики событий) в классе подписчика.

Объявление события (Event)

Чтобы объявить событие внутри класса, необходимо сначала объявить тип делегата для события. Например:

public delegate void BoilerLogHandler(string status);

Затем объявите само событие, используяeventКлючевое слово:

// 基于上面的委托定义事件
public event BoilerLogHandler BoilerEventLog;

Приведённый выше код определяет делегат с именемBoilerLogHandlerи событие с именемBoilerEventLog, которое вызывает делегат при его возникновении.

В следующем примере показано, как использовать события в C#:

Пример

using System;

namespace EventDemo
{
    // Определение типа делегата для обработчиков событий
    public delegate void NotifyEventHandler(object sender, EventArgs e);

    // Класс издателя
    public class ProcessBusinessLogic
    {
        // Объявление события
        public event NotifyEventHandler ProcessCompleted;

        // Метод для запуска события
        protected virtual void OnProcessCompleted(EventArgs e)
        {
            ProcessCompleted?.Invoke(this, e);
        }

        // Имитация процесса бизнес-логики и запуск событий
        public void StartProcess()
        {
            Console.WriteLine("Процесс запущен!");

            // Здесь можно добавить реальную бизнес-логику

            // Бизнес-логика завершена, вызвать событие
            OnProcessCompleted(EventArgs.Empty);
        }
    }

    // Класс подписчика
    public class EventSubscriber
    {
        public void Subscribe(ProcessBusinessLogic process)
        {
            process.ProcessCompleted += Process_ProcessCompleted;
        }

        private void Process_ProcessCompleted(object sender, EventArgs e)
        {
            Console.WriteLine("Процесс завершён!");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ProcessBusinessLogic process = new ProcessBusinessLogic();
            EventSubscriber subscriber = new EventSubscriber();

            // Подписка на событие
            subscriber.Subscribe(process);

            // Запуск процесса
            process.StartProcess();

            Console.ReadLine();
        }
    }
}

Описание

1. Определите тип делегата:

public delegate void NotifyEventHandler(object sender, EventArgs e);

Это тип делегата, который определяет сигнатуру обработчика событий. Обычно используетсяEventHandlerилиEventHandler<TEventArgs>для замены пользовательского делегата.

2. Объявление событий:

public event NotifyEventHandler ProcessCompleted;

Это событие, использующее тип делегата NotifyEventHandler.

3. Инициирование событий:

protected virtual void OnProcessCompleted(EventArgs e)
{
    ProcessCompleted?.Invoke(this, e);
}

Это защищённый метод, используемый для вызова события. Используйте?.Invokeсинтаксис, чтобы гарантировать, что событие вызывается только при наличии подписчиков.

4. Подписка на события и отписка от событий:

process.ProcessCompleted += Process_ProcessCompleted;

Использование подписчика+=оператор для подписки на событие и определения обработчика событияProcess_ProcessCompleted。

Пример

Пример 1

using System;
namespace SimpleEvent
{
  using System;
  /***********класс Publisher***********/
  public class EventTest
  {
    private int value;

    public delegate void NumManipulationHandler();


    public event NumManipulationHandler ChangeNum;
    protected virtual void OnNumChanged()
    {
      if ( ChangeNum != null )
      {
        ChangeNum(); /* Событие инициируется */
      }else {
        Console.WriteLine( "событие не сработало" );
        Console.ReadKey(); /* нажмите Enter, чтобы продолжить */
      }
    }


    public EventTest()
    {
      int n = 5;
      SetValue( n );
    }


    public void SetValue( int n )
    {
      if ( value != n )
      {
        value = n;
        OnNumChanged();
      }
    }
  }


  /***********Класс подписчика***********/

  public class subscribEvent
  {
    public void printf()
    {
      Console.WriteLine( "событие сработало" );
      Console.ReadKey(); /* нажмите Enter, чтобы продолжить */
    }
  }

  /***********запуск emit***********/
  public class MainClass
  {
    public static void Main()
    {
      EventTest e = new EventTest(); /* Создать экземпляр объекта, событие не срабатывает при первом выполнении */
      subscribEvent v = new subscribEvent(); /* Создать экземпляр объекта */
      e.ChangeNum += new EventTest.NumManipulationHandler( v.printf ); /* Регистрация */
      e.SetValue( 7 );
      e.SetValue( 11 );
    }
  }
}

Когда приведенный выше код скомпилирован и выполнен, он выдает следующие результаты:

event not fire
event fire
event fire

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

Пример 2

using System;
using System.IO;

namespace BoilerEventAppl
{
    // Класс Boiler
    class Boiler
    {
        public int Temp { get; private set; }
        public int Pressure { get; private set; }

        public Boiler(int temp, int pressure)
        {
            Temp = temp;
            Pressure = pressure;
        }
    }

    // Издатель событий
    class DelegateBoilerEvent
    {
        public delegate void BoilerLogHandler(string status);

        // Определить событие на основе вышеуказанного делегата
        public event BoilerLogHandler BoilerEventLog;

        public void LogProcess()
        {
            string remarks = "O.K.";
            Boiler boiler = new Boiler(100, 12);
            int temp = boiler.Temp;
            int pressure = boiler.Pressure;

            if (temp > 150 || temp < 80 || pressure < 12 || pressure > 15)
            {
                remarks = "Требуется техническое обслуживание";
            }

            OnBoilerEventLog($"Информация для журнала:\nТемпература: {temp}\nДавление: {pressure}\nСообщение: {remarks}");
        }

        protected void OnBoilerEventLog(string message)
        {
            BoilerEventLog?.Invoke(message);
        }
    }

    // Этот класс хранит условия для записи в файлы журнала
    class BoilerInfoLogger : IDisposable
    {
        private readonly StreamWriter _streamWriter;

        public BoilerInfoLogger(string filename)
        {
            _streamWriter = new StreamWriter(new FileStream(filename, FileMode.Append, FileAccess.Write));
        }

        public void Logger(string info)
        {
            _streamWriter.WriteLine(info);
        }

        public void Dispose()
        {
            _streamWriter?.Close();
        }
    }

    // Подписчик события
    public class RecordBoilerInfo
    {
        static void Logger(string info)
        {
            Console.WriteLine(info);
        }

        static void Main(string[] args)
        {
            using (BoilerInfoLogger fileLogger = new BoilerInfoLogger("e:\\boiler.txt"))
            {
                DelegateBoilerEvent boilerEvent = new DelegateBoilerEvent();
                boilerEvent.BoilerEventLog += Logger;
                boilerEvent.BoilerEventLog += fileLogger.Logger;
                boilerEvent.LogProcess();
            }

            Console.ReadLine();
        }
    }
}

Когда приведенный выше код скомпилирован и выполнен, он выдает следующие результаты:

Logging info:

Temperature 100
Pressure 12

Message: O. K
Другие расширения