C# Events

Summary: in this tutorial, you’ll learn about C# events and how to use events effectively to design the loose coupling applications.

Introduction to C# events

Events are something that occurs in a program. Events allow a class or object to notify other classes or objects when something occurs.

  • The class that raises (or sends) the event is called the publisher.
  • The classes that receive (or handle) the event are called subscribers. And the method of the classes that handle the event is often called event handlers.

This pattern is known as publisher/subscriber. In this pattern, the publisher determines when to raise the event and the subscribers decide how to handle the event.

Technically, an event has an encapsulated delegate. In fact, an event is like a simpler delegate. Let’s take an example of using events.

Suppose you have a class called Order with a method Create() that creates a new order:

class Order
{
    public void Create()
    {
        Console.WriteLine("Order created");
    }
}Code language: C# (cs)

And two other classes that send an email and SMS:

class Email 
{
    public static void Send()
    {
        Console.WriteLine("Send an email");
    }
}

class SMS
{
    public static void Send()
    {
        Console.WriteLine("Send an SMS");
    }
}Code language: C# (cs)

When an order is created, you want to send an email and SMS to the customer. To do it, you may come up with the following code:

class Order
{
    public void Create()
    {
        Console.WriteLine("Order was created");
        Email.Send();
        SMS.Send();
    }
}Code language: C# (cs)

Later if you want to do other tasks when an order is created, you have to modify the Create() method. Also, the Order class depends on the Email and SMS classes which is not a good design.

To resolve this, you can use the publisher/subscriber pattern:

  • The Order class is the publisher.
  • The Email and SMS classes are the subscribers.

When an order is created, the Order object will notify the Email and SMS classes to send an email and SMS.

Declaring an event

The following declares the OnCreated event when an order is created:

delegate void OrderEventHandler();

class Order
{
    public event OrderEventHandler OnCreated;

    public void Create()
    {
        Console.WriteLine("Order created");
    }
}Code language: C# (cs)

How it works.

First, define a delegate type for the event:

delegate void OrderEventHandler();Code language: C# (cs)

Second, declare an event associated with the delegate type:

public event OrderEventHandler OnCreated;Code language: C# (cs)

Since an event is a member of a class, you need to declare it inside the class. In this example, the event is public so that other classes can register event handlers with it. Also, the event handlers must match the delegate type associated with the event.

Raising an event

Raising an event is the same as invoking a method. An event that doesn’t have any event handlers is null. Therefore, before raising an event, you need to compare it to null.

The following raises the OnCreated event inside the Create() method:

class Order
{
    public event OrderEventHandler OnCreated;

    public void Create()
    {
        Console.WriteLine("Order created");
        
        if(OnCreated != null)
        {
            OnCreated();
        }
    }
}Code language: C# (cs)

Subscribing to an event

Subscribing to an event means adding event handlers to an event. The event handlers must have the same return type and signature as the event’s delegate.

To add an event handler to an event, you use the += operator. The event handler can be an instance method, a static method, an anonymous method, or a lambda expression.

The following shows how to subscribe OnCreated event:

class Program
{
    static void Main(string[] args)
    {
        var order = new Order();

        order.OnCreated += Email.Send;
        order.OnCreated += SMS.Send;

        order.Create();
    }
}Code language: C# (cs)

Output:

Order created
Send an email
Send an SMSCode language: C# (cs)

How it works.

First, create a new Order object:

var order = new Order();Code language: C# (cs)

Second, add event handlers to the OnCreated event:

order.OnCreated += Email.Send;
order.OnCreated += SMS.Send;Code language: C# (cs)

Third, call the Create() method of the Order object:

order.Create();Code language: C# (cs)

The Create() method raises the OnCreated event. Since the Email and SMS classes are subscribed to the OnCreated event, the Send() methods of these classes are automatically called.

Put it all together:

delegate void OrderEventHandler();

class Order
{
    public event OrderEventHandler OnCreated;

    public void Create()
    {
        Console.WriteLine("Order created");
        
        if(OnCreated != null)
        {
            OnCreated();
        }
    }
}


class Email 
{
    public static void Send()
    {
        Console.WriteLine($"Send an email");
    }
}

class SMS
{
    public static void Send()
    {
        Console.WriteLine($"Send an SMS");
    }
}

class Program
{
    static void Main(string[] args)
    {
        var order = new Order();

        order.OnCreated += Email.Send;
        order.OnCreated += SMS.Send;

        order.Create();
    }
}Code language: C# (cs)

EventHandler

C# provides you with the standard EventHandler delegate type so that you don’t need to define a new delegate type when you use events.

The following shows the declaration of the EventHandler delegate type:

public delegate void EventHandler(object sender, EventArgs e);Code language: C# (cs)

In this delegate type:

  • The sender holds a reference to the object that raised the event.
  • The EventArgs object holds the state information which can be whatever that is applicable to the application.

It’s important to understand that the EventArgs is designed for event handlers that do not need to pass data from the publisher to subscribers. If you want to pass the data, you need to define a class derived from the EventArgs class.

The following program shows how to use the EventHandler for the order created event:

class Order
{
    public event EventHandler OnCreated;

    public void Create()
    {
        Console.WriteLine("Order created");
        
        if(OnCreated != null)
        {
            OnCreated(this, EventArgs.Empty);
        }
    }
}


class Email 
{
    public static void Send(object sender, EventArgs e)
    {
        Console.WriteLine($"Send an email");
    }
}

class SMS
{
    public static void Send(object sender, EventArgs e)
    {
        Console.WriteLine($"Send an SMS");
    }
}


class Program
{
    static void Main(string[] args)
    {
        var order = new Order();

        order.OnCreated += Email.Send;
        order.OnCreated += SMS.Send;

        order.Create();
    }
}Code language: C# (cs)

How it works.

First, use the EventHandler instead of the OrderEventHandler delegate type:

public event EventHandler OnCreated;Code language: C# (cs)

Second, raise the OnCreated event by passing the Order object (this) and EventArgs.Empty:

OnCreated(this, EventArgs.Empty);Code language: C# (cs)

Note that the EventArgs.Empty provides a value to use with an event that does not have event data.

Third, modify the signature of the Send() method of the Email and SMS classes to match with the EventHandler delegate type:

public static void Send(object sender, EventArgs e)Code language: C# (cs)

Passing data by extending EventArgs

To pass data in the second parameter of the event handler from the publisher to subscribers, you need to define a class that inherits from the EventArgs class and store the data that you want to pass in the class.

The following program illustrates how to pass data (Email & Phone) from the publisher (Order class) to the subscribers ( Email and SMS classes).

class OrderEventArgs : EventArgs
{
    public string Email { get; set; }
    public string Phone { get; set; }
}

class Order
{
    public event EventHandler<OrderEventArgs> OnCreated;

    public void Create(string email, string phone)
    {
        Console.WriteLine("Order created");

        if(OnCreated != null)
        {
            OnCreated(this, new OrderEventArgs { Email = email, Phone = phone });
        }
    }
}

class Email 
{
    public static void Send(object sender, OrderEventArgs e)
    {
        Console.WriteLine($"Send an email to {e.Email}");
    }
}

class SMS
{
    public static void Send(object sender, OrderEventArgs e)
    {
        Console.WriteLine($"Send an SMS to {e.Phone}");
    }
}

class Program
{
    static void Main(string[] args)
    {
        var order = new Order();

        order.OnCreated += Email.Send;
        order.OnCreated += SMS.Send;

        order.Create("[email protected]", "(408)-111-2222");
    }
}Code language: C# (cs)

Output:

Order id 1 created with the amount 100
Send an email to john@test.com
Send an SMS to (408)-111-2222Code language: C# (cs)

How it works.

First, define the OrderEventArgs class that inherits from the EventArgs class:

class OrderEventArgs : EventArgs
{
    public string Email { get; set; }
    public string Phone { get; set; }
}Code language: C# (cs)

Second, define the event using the EventHanlder with the OrderEventArgs type:

public event EventHandler<OrderEventArgs> OnCreated;Code language: C# (cs)

Third, raise an event and a new instance of the OrderEventArgs class:

OnCreated(this, new OrderEventArgs { Email = email, Phone = phone });Code language: C# (cs)

In this statement, the OrderEventArgs object contains the email and phone data.

Fourth, change the Send() method’s signature to use the OrderEventArgs:

public static void Send(object sender, OrderEventArgs e)Code language: C# (cs)

Inside the Send() method, you can access the email & phone number via the OrderEventArgs object.

Summary

  • Events allow a class or object to notify other classes or objects when something occurs.
  • Events are used in a publisher/subscriber pattern in which the publisher raises an event and the subscribers respond to the event.
  • Use EventHandler as the delegate type to declare an event.
  • Extend the EventArgs class to pass data from the publisher to subscribers.
Was this tutorial helpful ?