Event unsubscription and memory in C Sharp (C#) - Time & Space Complexity
When working with events in C#, it's important to understand how unsubscribing affects program performance and memory.
We want to see how the time to unsubscribe grows as more event handlers are attached.
Analyze the time complexity of unsubscribing event handlers from an event.
public class Publisher
{
public event EventHandler? OnChange;
public void UnsubscribeAll()
{
if (OnChange == null) return;
foreach (Delegate d in OnChange.GetInvocationList())
{
OnChange -= (EventHandler)d;
}
}
}
This code removes all handlers subscribed to the OnChange event one by one.
Look for loops or repeated actions in the code.
- Primary operation: Looping through each subscribed event handler.
- How many times: Once for each handler attached to the event.
The time to unsubscribe grows as the number of handlers increases.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 loop steps to remove handlers |
| 100 | About 100 loop steps to remove handlers |
| 1000 | About 1000 loop steps to remove handlers |
Pattern observation: The work grows directly with the number of handlers.
Time Complexity: O(n)
This means the time to unsubscribe all handlers grows linearly with how many handlers there are.
[X] Wrong: "Unsubscribing from an event is always a constant time operation."
[OK] Correct: Because unsubscribing here loops through all handlers, so more handlers mean more time needed.
Understanding how event unsubscription scales helps you write efficient and memory-safe C# programs, a useful skill in many coding situations.
What if we stored handlers in a different data structure that allowed direct removal? How would the time complexity change?
Practice
Solution
Step 1: Understand event subscription behavior
When an object subscribes to an event, the event publisher holds a reference to the subscriber's method.Step 2: Effect of not unsubscribing
If you don't unsubscribe, the subscriber object remains referenced and cannot be garbage collected, causing a memory leak.Final Answer:
The subscriber object may not be garbage collected, causing a memory leak. -> Option CQuick Check:
Not unsubscribing = memory leak [OK]
- Assuming events auto-unsubscribe
- Thinking unsubscribing causes errors
- Believing event handlers run only once
OnDataReceived from an event DataReceived?Solution
Step 1: Recall event unsubscription syntax
In C#, to unsubscribe from an event, use the '-=' operator with the same method.Step 2: Match correct syntax
DataReceived -= OnDataReceived; uses 'DataReceived -= OnDataReceived;', which is the correct way to unsubscribe.Final Answer:
DataReceived -= OnDataReceived; -> Option AQuick Check:
Unsubscribe syntax = '-=' operator [OK]
- Using '+=' instead of '-=' to unsubscribe
- Trying to assign null to the event
- Using non-existent Unsubscribe method
using System;
class Program {
static event Action MyEvent;
static void Handler() => Console.WriteLine("Called");
static void Main() {
MyEvent += Handler;
MyEvent -= Handler;
MyEvent?.Invoke();
}
}Solution
Step 1: Analyze event subscription and unsubscription
The method Handler is subscribed then immediately unsubscribed from MyEvent.Step 2: Check event invocation
Since no handlers remain, MyEvent is null, so MyEvent?.Invoke() does nothing and prints no output.Final Answer:
No output -> Option BQuick Check:
Unsubscribed event = no call [OK]
- Expecting output despite unsubscription
- Ignoring null conditional operator
- Thinking event throws exception if empty
class Publisher {
public event Action OnChange;
public void Raise() => OnChange?.Invoke();
}
class Subscriber {
public void Subscribe(Publisher p) {
p.OnChange += HandleChange;
}
void HandleChange() {
Console.WriteLine("Changed");
}
}Solution
Step 1: Review subscription and unsubscription
The Subscriber subscribes to the event but never unsubscribes.Step 2: Understand consequences
Without unsubscription, the Subscriber object remains referenced by Publisher, causing memory leaks.Final Answer:
Subscriber never unsubscribes, causing potential memory leaks. -> Option AQuick Check:
Missing unsubscribe = memory leak risk [OK]
- Ignoring unsubscription importance
- Confusing static and instance events
- Assuming null conditional operator causes errors
Solution
Step 1: Understand static event references
Static events hold references for the app lifetime, so subscribers never get garbage collected unless unsubscribed.Step 2: Best practice to avoid leaks
Using weak event patterns or explicitly unsubscribing prevents memory leaks by releasing subscriber references.Final Answer:
Use weak event patterns or explicitly unsubscribe when subscribers are no longer needed. -> Option DQuick Check:
Weak events or unsubscribe = prevent leaks [OK]
- Assuming GC cleans static event subscribers
- Changing event to instance-level without reason
- Replacing events with inefficient polling
Ready to prove it?
Pass the test and this pattern moves unknown
