C# Event
C# events (Event) are members used to send specific event notifications to subscribers. Events are typically used to implement the observer pattern, which allows an object to notify other objects of state changes without needing to know the details of those objects.
EventBasically, it is a user operation, such as key presses, clicks, mouse movements, etc., or some prompt information, such as system-generated notifications. Applications need to respond to events when they occur. For example, interrupts.
In C#, the event mechanism is used to implement communication between threads.
Key points:
- Declare delegate: Define the delegate type that the event will use. A delegate is a function signature.
- Declare event: Use
eventThe keyword declares an event. - Trigger event: Invoke the event at an appropriate time to notify all subscribers.
- Subscribing to and unsubscribing from events: Other classes can
+=and-=use operators to subscribe to and unsubscribe from events.
Using delegates through events
Events are declared and raised in a class, and are associated with event handlers via delegates in the same class or other classes. The class that contains the event is used to publish the event. This is calledPublisher (publisher)classes. Other classes that accept this event are calledSubscriberClass. Event usagepublish-subscribe (publisher-subscriber)Model.
Publisher (publisher)Is an object that contains event and delegate definitions. The connection between the event and the delegate is also defined in this object. An object of the publisher class invokes this event and notifies other objects.
SubscriberIs an object that accepts an event and provides an event handler. The delegate in the publisher class calls methods (event handlers) in the subscriber class.
Declare an event (Event)
To declare an event inside a class, you must first declare the delegate type for the event. For example:
public delegate void BoilerLogHandler(string status);
Then, declare the event itself, usingeventKeyword:
// 基于上面的委托定义事件 public event BoilerLogHandler BoilerEventLog;
The code above defines a namedBoilerLogHandlerdelegate and a namedBoilerEventLogevent, which invokes the delegate when it is raised.
The following example shows how to use events in C#:
Example
namespace EventDemo
{
// Define a delegate type for event handlers
public delegate void NotifyEventHandler(object sender, EventArgs e);
// Publisher class
public class ProcessBusinessLogic
{
// Declare event
public event NotifyEventHandler ProcessCompleted;
// method to trigger event
protected virtual void OnProcessCompleted(EventArgs e)
{
ProcessCompleted?.Invoke(this, e);
}
// Simulate business logic process and trigger events
public void StartProcess()
{
Console.WriteLine("Process Started!");
// You can add actual business logic here
// Business logic completed, trigger event
OnProcessCompleted(EventArgs.Empty);
}
}
// Subscriber class
public class EventSubscriber
{
public void Subscribe(ProcessBusinessLogic process)
{
process.ProcessCompleted += Process_ProcessCompleted;
}
private void Process_ProcessCompleted(object sender, EventArgs e)
{
Console.WriteLine("Process Completed!");
}
}
class Program
{
static void Main(string[] args)
{
ProcessBusinessLogic process = new ProcessBusinessLogic();
EventSubscriber subscriber = new EventSubscriber();
// Subscribe to event
subscriber.Subscribe(process);
// Startup process
process.StartProcess();
Console.ReadLine();
}
}
}
Description
1. Define the delegate type:
public delegate void NotifyEventHandler(object sender, EventArgs e);
This is a delegate type that defines the signature of the event handler. Usually useEventHandlerorEventHandler<TEventArgs>to replace a custom delegate.
2. Declaring events:
public event NotifyEventHandler ProcessCompleted;
This is an event that uses the NotifyEventHandler delegate type.
3. Triggering events:
protected virtual void OnProcessCompleted(EventArgs e)
{
ProcessCompleted?.Invoke(this, e);
}This is a protected method used to raise the event. Use?.Invokesyntax to ensure that the event is invoked only when there are subscribers.
4. Subscribing to and unsubscribing from events:
process.ProcessCompleted += Process_ProcessCompleted;
Subscriber usage+=operator to subscribe to an event and define an event handlerProcess_ProcessCompleted。
Example
Example 1
namespace SimpleEvent
{
using System;
/***********Publisher class***********/
public class EventTest
{
private int value;
public delegate void NumManipulationHandler();
public event NumManipulationHandler ChangeNum;
protected virtual void OnNumChanged()
{
if ( ChangeNum != null )
{
ChangeNum(); /* Event is triggered */
}else {
Console.WriteLine( "event not fire" );
Console.ReadKey(); /* press Enter to continue */
}
}
public EventTest()
{
int n = 5;
SetValue( n );
}
public void SetValue( int n )
{
if ( value != n )
{
value = n;
OnNumChanged();
}
}
}
/***********Subscriber class***********/
public class subscribEvent
{
public void printf()
{
Console.WriteLine( "event fire" );
Console.ReadKey(); /* press Enter to continue */
}
}
/***********触emit***********/
public class MainClass
{
public static void Main()
{
EventTest e = new EventTest(); /* Instantiate object, event not triggered on first time */
subscribEvent v = new subscribEvent(); /* Instantiate the object */
e.ChangeNum += new EventTest.NumManipulationHandler( v.printf ); /* Register */
e.SetValue( 7 );
e.SetValue( 11 );
}
}
}
When the above code is compiled and executed, it produces the following results:
event not fire event fire event fire
This example provides a simple application for troubleshooting a hot water boiler system. When the maintenance engineer inspects the boiler, the boiler's temperature and pressure, along with the maintenance engineer's remarks, are automatically recorded in the log file.
Example 2
using System.IO;
namespace BoilerEventAppl
{
// Boiler class
class Boiler
{
public int Temp { get; private set; }
public int Pressure { get; private set; }
public Boiler(int temp, int pressure)
{
Temp = temp;
Pressure = pressure;
}
}
// Event publisher
class DelegateBoilerEvent
{
public delegate void BoilerLogHandler(string status);
// Define event based on the above delegate
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 = "Need Maintenance";
}
OnBoilerEventLog($"Logging Info:\nTemperature: {temp}\nPressure: {pressure}\nMessage: {remarks}");
}
protected void OnBoilerEventLog(string message)
{
BoilerEventLog?.Invoke(message);
}
}
// This class retains the terms for writing to log files
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();
}
}
// Event subscriber
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();
}
}
}
When the above code is compiled and executed, it produces the following results:
Logging info: Temperature 100 Pressure 12 Message: O. Kother extensions