C#
event subscriptions
.NET
programming
software development

How can I clear event subscriptions in C?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

In C#, events maintain an invocation list of subscribed delegate handlers. Clearing all subscriptions is necessary to prevent memory leaks (publisher keeping subscribers alive), avoid duplicate handler invocations after re-subscription, and reset state during testing. Inside the declaring class, you can set the event to null to remove all handlers. Outside the class, you can only use -= to remove specific handlers. There is no built-in way to clear all event subscriptions from external code without using reflection.

How Events Store Subscriptions

csharp
1public class Button
2{
3    // The event keyword wraps a delegate with add/remove accessors
4    public event EventHandler Click;
5
6    // Internally, Click is a multicast delegate
7    // Each += adds a handler to the invocation list
8    // Each -= removes a handler
9
10    public void SimulateClick()
11    {
12        Click?.Invoke(this, EventArgs.Empty);
13    }
14}

Clearing All Subscriptions from Inside the Class

csharp
1public class Button
2{
3    public event EventHandler Click;
4
5    // Inside the declaring class, you can set the event to null
6    public void ClearClickHandlers()
7    {
8        Click = null;  // Removes ALL subscriptions
9    }
10
11    public void SimulateClick()
12    {
13        Click?.Invoke(this, EventArgs.Empty);
14    }
15
16    public int SubscriberCount => Click?.GetInvocationList().Length ?? 0;
17}
18
19// Usage
20var button = new Button();
21button.Click += (s, e) => Console.WriteLine("Handler 1");
22button.Click += (s, e) => Console.WriteLine("Handler 2");
23Console.WriteLine(button.SubscriberCount);  // 2
24
25button.ClearClickHandlers();
26Console.WriteLine(button.SubscriberCount);  // 0

Removing Specific Handlers with -=

csharp
1public class EventPublisher
2{
3    public event EventHandler<string> MessageReceived;
4
5    public void RaiseMessage(string msg)
6    {
7        MessageReceived?.Invoke(this, msg);
8    }
9}
10
11// Subscribe with a named method (can be unsubscribed)
12void HandleMessage(object sender, string msg) => Console.WriteLine(msg);
13
14var publisher = new EventPublisher();
15publisher.MessageReceived += HandleMessage;
16
17// Later, unsubscribe
18publisher.MessageReceived -= HandleMessage;

Anonymous lambdas cannot be unsubscribed because you do not have a reference to the original delegate instance:

csharp
1// PROBLEM: cannot unsubscribe anonymous lambdas
2publisher.MessageReceived += (s, e) => Console.WriteLine(e);
3publisher.MessageReceived -= (s, e) => Console.WriteLine(e);
4// Does NOT remove the handler — this is a different delegate instance

Pattern: Store Handler Reference for Later Removal

csharp
1EventHandler<string> handler = (s, e) => Console.WriteLine(e);
2
3publisher.MessageReceived += handler;
4// ... later
5publisher.MessageReceived -= handler;  // Works — same delegate instance

Clearing Events via Reflection (External Code)

When you do not own the class and need to clear its events (e.g., in testing):

csharp
1using System.Reflection;
2
3public static void ClearEventHandlers(object obj, string eventName)
4{
5    var type = obj.GetType();
6    var fieldInfo = type.GetField(eventName,
7        BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
8
9    if (fieldInfo != null)
10    {
11        fieldInfo.SetValue(obj, null);
12        return;
13    }
14
15    // For events backed by EventHandlerList (WinForms controls)
16    var eventInfo = type.GetEvent(eventName);
17    if (eventInfo != null)
18    {
19        var backingField = type.GetField(eventName,
20            BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance |
21            BindingFlags.FlattenHierarchy);
22        backingField?.SetValue(obj, null);
23    }
24}
25
26// Usage
27ClearEventHandlers(button, "Click");

This is fragile and should only be used in testing. The backing field name may differ from the event name in some implementations.

Weak Event Pattern (Preventing Memory Leaks)

csharp
1// .NET provides WeakEventManager for WPF
2// For general use, implement a weak reference wrapper
3
4public class WeakEvent<THandler> where THandler : Delegate
5{
6    private readonly List<WeakReference<THandler>> _handlers = new();
7
8    public void Subscribe(THandler handler)
9    {
10        _handlers.Add(new WeakReference<THandler>(handler));
11    }
12
13    public void Raise(Action<THandler> invoker)
14    {
15        _handlers.RemoveAll(wr => !wr.TryGetTarget(out _));
16        foreach (var wr in _handlers.ToList())
17        {
18            if (wr.TryGetTarget(out var handler))
19                invoker(handler);
20        }
21    }
22}

Common Pitfalls

  • Anonymous lambdas cannot be unsubscribed: Subscribing with event += (s, e) => ... creates a delegate you have no reference to. Calling -= with an identical lambda creates a new delegate instance that does not match the original. Always store the delegate in a variable if you need to unsubscribe later.
  • Forgetting to unsubscribe causes memory leaks: If the event publisher has a longer lifetime than the subscriber, the subscription keeps the subscriber alive via the delegate reference. The garbage collector cannot collect the subscriber. Unsubscribe in Dispose() or use the weak event pattern.
  • Setting event to null from outside the class: button.Click = null is a compile error. The event keyword restricts external code to += and -= only. Only code inside the declaring class can assign null to the event. Provide a ClearHandlers() method if external clearing is needed.
  • Double-subscribing the same handler: Calling event += handler twice adds the handler to the invocation list twice — it will be called twice per event raise. Either check before subscribing or unsubscribe first: event -= handler; event += handler;.
  • Thread safety when clearing events: Setting an event to null while another thread is raising it can cause a NullReferenceException. Use the event?.Invoke() pattern and consider locking if events are raised from multiple threads.

Summary

  • Inside the declaring class, set the event to null to clear all subscriptions
  • Outside the class, use -= with a stored delegate reference to remove specific handlers
  • Anonymous lambdas cannot be unsubscribed — always store the delegate reference
  • Provide a ClearHandlers() method on your class if external clearing is needed
  • Unsubscribe in Dispose() to prevent memory leaks from long-lived publishers

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.