C# - Events
In C#, events are a way for a class to notify other classes or objects when something happens. They are typically used in scenarios where one class needs to react to an action performed by another class, following the publisher-subscriber model. Events are built on delegates and provide a mechanism for communication between objects in a decoupled way.
Key Features of Events:
- Encapsulation of Delegates: Events encapsulate delegates, restricting the way they can be accessed and invoked.
- Publisher-Subscriber Model: The class that raises the event is called the "publisher," and the classes that handle the event are called "subscribers."
- Delegates as Event Handlers: When an event is raised, the methods subscribed to the event (called event handlers) are invoked.
- Multicast: Multiple methods can subscribe to the same event.
Syntax:
- Declaring an Event: An event is declared using the
event
keyword followed by a delegate type. - Raising an Event: The event is raised by the publisher class when a specific action occurs.
Example:
Defining a Delegate Type for the Event:
csharppublic delegate void Notify(); // Delegate type
Defining a Publisher Class:
csharppublic class Publisher { // Declare an event of delegate type Notify public event Notify OnProcessCompleted; // Method to trigger the event public void Process() { Console.WriteLine("Process Started..."); // After some processing, raise the event OnProcessCompleted?.Invoke(); // Safe invocation using null conditional operator Console.WriteLine("Process Completed."); } }
Subscribing to an Event (in Subscriber Class):
csharppublic class Subscriber { public void Subscribe(Publisher publisher) { // Subscribe the method to the event publisher.OnProcessCompleted += EventHandler; } // This method will be called when the event is raised void EventHandler() { Console.WriteLine("Subscriber received the ProcessCompleted event."); } }
Using the Event:
csharpclass Program { static void Main() { Publisher publisher = new Publisher(); Subscriber subscriber = new Subscriber(); // Subscribe to the event subscriber.Subscribe(publisher); // Trigger the process, which will raise the event publisher.Process(); } }
Output:
arduinoProcess Started...
Subscriber received the ProcessCompleted event.
Process Completed.
Event with EventArgs:
To provide more information when an event is raised, events often use the EventHandler
delegate or a custom delegate with a parameter of type EventArgs
.
Example of Event with EventArgs:
Defining Custom EventArgs:
csharppublic class ProcessEventArgs : EventArgs { public string Message { get; } public ProcessEventArgs(string message) { Message = message; } }
Defining an Event with EventArgs:
csharppublic class Publisher { public event EventHandler<ProcessEventArgs> OnProcessCompleted; public void Process() { Console.WriteLine("Process Started..."); // Raise the event with custom event args OnProcessCompleted?.Invoke(this, new ProcessEventArgs("Process completed successfully")); Console.WriteLine("Process Completed."); } }
Subscribing to the Event:
csharppublic class Subscriber { public void Subscribe(Publisher publisher) { publisher.OnProcessCompleted += EventHandler; } // Event handler that takes sender and EventArgs void EventHandler(object sender, ProcessEventArgs e) { Console.WriteLine($"Subscriber received the event: {e.Message}"); } }
Using the Event with EventArgs:
csharpclass Program { static void Main() { Publisher publisher = new Publisher(); Subscriber subscriber = new Subscriber(); // Subscribe to the event subscriber.Subscribe(publisher); // Trigger the process publisher.Process(); } }
Output:
arduinoProcess Started...
Subscriber received the event: Process completed successfully
Process Completed.
Key Points:
- Delegates and Events: Events are based on delegates, but they provide a more restricted interface, as events can only be triggered by the class that declares them.
- Multicasting: Multiple subscribers can handle the same event.
- EventArgs: You can pass additional data to event handlers using
EventArgs
or a derived class. - Null Conditional Operator: When raising an event, use
?.Invoke
to ensure that the event has subscribers before calling it.