Skip to main content
๐Ÿ“œ WAYPOINT LESSON

EventArgs Contracts and Lifetime Hygiene

โญโญ intermediateโณ 15 min read๐Ÿ“ Lesson 99 of 265

EventHandler<T>, custom args records, unsubscribe discipline, and the static-event leak.

The contract: sender + args

EventHandler<TEventArgs> is void(object? sender, TEventArgs e) with a name that says what it is. Custom args carry everything a handler needs โ€” and nothing it doesn't:

public sealed record TemperatureChangedEventArgs(
    string Sensor, double OldValue, double NewValue);

public class Thermometer
{
    public event EventHandler<TemperatureChangedEventArgs>? Changed;

    public double Value { get; private set; }

    public void Read(double newValue)
    {
        double old = Value;
        Value = newValue;
        Changed?.Invoke(this, new TemperatureChangedEventArgs("t1", old, newValue));
    }
}

Design rule: args are a snapshot at raise time. Handlers must not mutate the publisher through them; if a handler needs to influence the outcome, that is not an event โ€” that is a callback (use Func or CancelEventArgs-style mutable args deliberately).

Unsubscribe is part of the contract

+= without a matching -= pins the subscriber for the publisher's lifetime. Long-lived publishers (singletons, static events) + short-lived subscribers = the leak:

var t = new Thermometer();
t.Changed += OnChanged;      // static OnChanged, but t is now pinned by it
t.Changed -= OnChanged;      // only this releases t

Worse: SomeStaticClass.Event += handler holds subscribers forever. Static events are a deliberate lifetime decision, not a convenience.

Check your understanding

  • Why snapshot args at raise time? (Handlers run later than the state change.)
  • When is a static event acceptable? (When every subscriber lives as long as the process.)

โšก Now practice

Ready to Code
Events Practice: Publish, Subscribe, UnsubscribeEncapsulated multicast in action โ€” wire a publisher, custom EventArgs, replacement semantics, and unsubscribe hygiene.
2 challenges ยท ยท ~25 min