Super-Simple Implementation of Observer Pattern in C#: Delegates and Events Explained

Dec 07, 2025 · Programming · 9 views · 7.8

Keywords: C# | Observer Pattern | Delegates | Events | Design Patterns

Abstract: This article explores the implementation of the observer pattern in C#, demonstrating how to use delegates and events to build the observer-observable pattern through a concise example. It explains event declaration, event triggering, the use of null-conditional operators, and compares implementations across different C# versions, helping readers master the practical application of this core design pattern in C#.

Introduction

The observer pattern is a widely used behavioral pattern in software design that defines a one-to-many dependency between objects. When a subject object changes its state, all its dependent observers are notified and updated automatically. In C#, this pattern is elegantly implemented through delegates and events.

Core Concepts: Delegates and Events

In C#, a delegate is a type-safe function pointer that allows methods to be passed as parameters or stored. An event is a special form of delegate that provides a standardized implementation for the observer pattern. Events encapsulate delegates, ensuring they can only be invoked from the class that declares them, offering better encapsulation and safety.

Implementation Example

Here is a super-simple example of implementing the observer pattern in C# using events:

using System;

class Observable
{
    public event EventHandler SomethingHappened;

    public void DoSomething() =>
        SomethingHappened?.Invoke(this, EventArgs.Empty);
}

class Observer
{
    public void HandleEvent(object sender, EventArgs args)
    {
        Console.WriteLine("Something happened to " + sender);
    }
}

class Test
{
    static void Main()
    {
        Observable observable = new Observable();
        Observer observer = new Observer();
        observable.SomethingHappened += observer.HandleEvent;

        observable.DoSomething();
    }
}

Code Analysis

In this example, the Observable class defines a SomethingHappened event of type EventHandler delegate. When the DoSomething method is called, the event is safely triggered using the null-conditional operator ?.. If no observers have subscribed to the event, SomethingHappened will be null, and the null-conditional operator prevents a null reference exception.

The Observer class contains the HandleEvent method, which matches the signature of the EventHandler delegate: it accepts an object sender and EventArgs arguments. In the Main method of the Test class, instances of the observable and observer are created, and the observer's handler method is subscribed to the event using the += operator.

Compatibility Considerations

The above example uses the null-conditional operator introduced in C# 6. For implementations in older versions of C#, the following code can be used:

public void DoSomething()
{
    var handler = SomethingHappened;
    if (handler != null)
    {
        handler(this, EventArgs.Empty);
    }
}

This implementation copies the event delegate to a local variable handler, avoiding race conditions in multithreaded environments and ensuring thread safety during event invocation.

Design Advantages

Using events to implement the observer pattern offers several advantages: first, events provide standard subscription and unsubscription mechanisms (+= and -= operators), making code clearer and more readable; second, events restrict external code to only subscribe and unsubscribe, preventing direct invocation or clearing, which enhances encapsulation; finally, the EventHandler delegate in the .NET framework provides a unified foundation for standard event patterns.

Practical Application Scenarios

The observer pattern is widely applied in C# development, particularly in user interface programming. For example, in Windows Forms or WPF applications, button click events and textbox text change events are typical applications of the observer pattern. Additionally, the pattern plays a crucial role in asynchronous programming, message-passing systems, and real-time data updates.

Conclusion

Through delegates and events, C# provides a concise and powerful implementation of the observer pattern. The super-simple example demonstrated in this article reveals the core principle of this pattern: observable objects notify observers of state changes via events, and observers receive notifications and respond by subscribing to events. Mastering this pattern not only helps in writing more modular and maintainable code but also deepens the understanding of the design philosophy behind C#'s event system.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.