Events notify other classes and objects when the desired action occurs in a class or object. A delegate is a type-safe function pointer that defines a method signature in CLI.
In .NET, events and delegates are key components of the event-driven programming model.
- Delegates: Delegates are objects that refer to methods. They are similar to function pointers in C or C++, but they are type-safe and object-oriented. Delegates allow methods to be passed as parameters, returned from methods, and stored in data structures. They are essentially function pointers with type safety and are used to define callback methods and implement event handling, among other things.
- Events: Events are a way for objects to notify other objects when something of interest happens. They are a higher-level abstraction built upon delegates. An event is essentially a member of a class that allows other objects to register as listeners for certain occurrences. When the event is triggered, all registered listeners (delegates) are invoked. Events provide a way for objects to communicate without needing to know the details of each other’s implementations, promoting loose coupling.
Here’s a brief overview of how they work together:
- A class declares an event using the
event
keyword. - The event is associated with a delegate type that defines the signature of the methods that can be registered as event handlers.
- Other classes can subscribe to the event by adding a method (or methods) to the event delegate’s invocation list using the
+=
operator. - When the event occurs, the class raising the event invokes the delegate, which in turn calls all the subscribed methods.
- Subscribers can unsubscribe from the event using the
-=
operator.
Here’s a simple example in C#:
using System;
// Define a delegate
public delegate void EventHandler(object sender, EventArgs e);
// Define a class that contains an event
public class Publisher
{
public event EventHandler SomethingHappened;
public void DoSomething()
{
Console.WriteLine("Something is happening...");
OnSomethingHappened(EventArgs.Empty);
}
protected virtual void OnSomethingHappened(EventArgs e)
{
SomethingHappened?.Invoke(this, e);
}
}
// Define a class that handles the event
public class Subscriber
{
public void HandleEvent(object sender, EventArgs e)
{
Console.WriteLine("Something happened!");
}
}
class Program
{
static void Main(string[] args)
{
Publisher publisher = new Publisher();
Subscriber subscriber = new Subscriber();
// Subscribe to the event
publisher.SomethingHappened += subscriber.HandleEvent;
// Trigger the event
publisher.DoSomething();
// Unsubscribe from the event
publisher.SomethingHappened -= subscriber.HandleEvent;
}
}
In this example, Publisher
declares an event named SomethingHappened
, which is associated with the EventHandler
delegate. Subscriber
defines a method HandleEvent
that matches the signature of EventHandler
, which is used as the event handler. When DoSomething
is called on the Publisher
, it raises the SomethingHappened
event, which invokes all the subscribed event handlers, including HandleEvent
in Subscriber
.