Introduction

Delegates and events are powerful features in C# that enable developers to write flexible and reusable code. Delegates are similar to function pointers in C++ but are type-safe. Events provide a way for a class to notify other classes or objects when something of interest occurs.

Key Concepts

Delegates

  • Definition: A delegate is a type that represents references to methods with a particular parameter list and return type.
  • Usage: Delegates are used to pass methods as arguments to other methods, define callback methods, and implement event handling.

Events

  • Definition: An event is a message sent by an object to signal the occurrence of an action.
  • Usage: Events are used to provide notifications and are typically used in conjunction with delegates.

Delegates

Declaring a Delegate

// Delegate declaration
public delegate void MyDelegate(string message);

Instantiating and Using a Delegate

using System;

public class Program
{
    // Delegate declaration
    public delegate void MyDelegate(string message);

    // Method that matches the delegate signature
    public static void DisplayMessage(string message)
    {
        Console.WriteLine(message);
    }

    public static void Main()
    {
        // Instantiating the delegate
        MyDelegate del = new MyDelegate(DisplayMessage);

        // Using the delegate
        del("Hello, World!");
    }
}

Explanation:

  • The MyDelegate delegate is declared to accept a string parameter and return void.
  • The DisplayMessage method matches the delegate signature.
  • The delegate is instantiated and used to call the DisplayMessage method.

Multicast Delegates

Delegates can reference more than one method. These are called multicast delegates.

using System;

public class Program
{
    public delegate void MyDelegate(string message);

    public static void DisplayMessage(string message)
    {
        Console.WriteLine("DisplayMessage: " + message);
    }

    public static void LogMessage(string message)
    {
        Console.WriteLine("LogMessage: " + message);
    }

    public static void Main()
    {
        MyDelegate del = DisplayMessage;
        del += LogMessage;

        del("Hello, Multicast!");
    }
}

Explanation:

  • The MyDelegate delegate references both DisplayMessage and LogMessage methods.
  • When the delegate is invoked, both methods are called in sequence.

Events

Declaring an Event

public class Publisher
{
    // Declare the delegate for the event
    public delegate void Notify(string message);

    // Declare the event using the delegate
    public event Notify OnNotify;
}

Raising an Event

public class Publisher
{
    public delegate void Notify(string message);
    public event Notify OnNotify;

    public void RaiseEvent(string message)
    {
        if (OnNotify != null)
        {
            OnNotify(message);
        }
    }
}

Subscribing to an Event

using System;

public class Subscriber
{
    public void OnNotified(string message)
    {
        Console.WriteLine("Subscriber received: " + message);
    }
}

public class Program
{
    public static void Main()
    {
        Publisher publisher = new Publisher();
        Subscriber subscriber = new Subscriber();

        // Subscribe to the event
        publisher.OnNotify += subscriber.OnNotified;

        // Raise the event
        publisher.RaiseEvent("Event triggered!");
    }
}

Explanation:

  • The Publisher class declares an event OnNotify using the Notify delegate.
  • The RaiseEvent method raises the event if there are any subscribers.
  • The Subscriber class has a method OnNotified that matches the delegate signature.
  • In the Main method, the Subscriber subscribes to the Publisher's event, and the event is raised.

Practical Exercises

Exercise 1: Basic Delegate

Task: Create a delegate that takes an integer and returns its square.

public delegate int SquareDelegate(int number);

public class Program
{
    public static int Square(int number)
    {
        return number * number;
    }

    public static void Main()
    {
        SquareDelegate del = Square;
        Console.WriteLine(del(5)); // Output: 25
    }
}

Exercise 2: Event Handling

Task: Create a simple event system where a Button class raises a Clicked event, and a Handler class subscribes to it.

public class Button
{
    public delegate void ClickHandler();
    public event ClickHandler Clicked;

    public void Click()
    {
        if (Clicked != null)
        {
            Clicked();
        }
    }
}

public class Handler
{
    public void OnButtonClicked()
    {
        Console.WriteLine("Button was clicked!");
    }
}

public class Program
{
    public static void Main()
    {
        Button button = new Button();
        Handler handler = new Handler();

        button.Clicked += handler.OnButtonClicked;

        button.Click(); // Output: Button was clicked!
    }
}

Common Mistakes and Tips

  • Null Reference: Always check if the event is null before raising it to avoid NullReferenceException.
  • Delegate Signature: Ensure the method signature matches the delegate signature when assigning methods to delegates.
  • Unsubscribing: Remember to unsubscribe from events to prevent memory leaks, especially in long-running applications.

Conclusion

Delegates and events are essential tools in C# for creating flexible and maintainable code. Delegates allow methods to be passed as parameters, while events provide a mechanism for implementing the observer pattern. Understanding these concepts will enable you to write more dynamic and responsive applications.

© Copyright 2024. All rights reserved