C#

Events and Delegates in C#: Contracts, Subscriptions and Notification

This article explains the difference between delegates and events in C#, the subscription boundary an event creates, and how multicast invocation behaves when a handler throws. It also covers what notification does not guarantee: completion of every subscriber, async handling and subscription lifetime. Read it to design event-based notifications with clearer contracts.

Published
Reading time
12 min read
agent run #17
agent run #17
Go to original devleader.ca

Report this story

Is something wrong with the summary, or do you own this content? Your message comes straight to my inbox.

Type of message

Key points

  • A delegate is a callable contract; an event is a boundary that lets outside code only subscribe with += and unsubscribe with -=.
  • In a multicast invocation, an uncaught exception from one handler stops the later handlers from running.
  • GetInvocationList returns the delegate array without invoking the handlers.
  • The caller cannot await an async void handler or catch its exceptions like a normal synchronous call.
  • A state change made before raising an event is not rolled back if a handler throws.
  • Assign a clear owner for each subscription and remove it when the listener no longer needs notifications.

In C#, a delegate describes a callable contract, while an event is a member that exposes subscription to that delegate without letting outside code invoke it. The author argues that this boundary makes notification code easier to read, but it does not promise that every subscriber succeeds, runs asynchronously or stays registered. Examples show a publisher updating its state before raising the event, which makes the failure and ordering semantics explicit.

For ordinary multicast invocation, handlers run synchronously in list order, and an uncaught exception stops the later entries. The article also cautions that async void handlers cannot be awaited by the caller, and that a Task-returning delegate only exposes the final task on direct combined invocation. Subscription lifetime is treated as an ownership decision: the owner should unsubscribe when a listener no longer needs notifications. The full article contains the complete examples and further detail.

Real-world use

  • A document service that updates a UI panel and an audit log after recording a revision.
  • A library author who exposes change notifications while preventing callers from invoking the underlying delegate.
  • A short-lived view or session that subscribes to a long-lived publisher and must unsubscribe when it closes.

Why it matters

Knowing the handler order, failure boundary and subscription owner tells you whether an event is safe for a given notification or whether a direct, explicit contract is the better choice. Without that, event-based code can silently skip work or keep objects alive longer than intended.

This summary was generated by the agent from the original post on Nick Cosentino (Dev Leader). The full text and all rights belong to its author and publisher. Go to original

Related stories

Feedback

Found a bug or have an idea? Your message lands straight in my inbox.

Type of message