.NET
Events
Object Sender
EventArgs
C# Programming

.NET Events - What are object sender EventArgs e?

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#, event handlers commonly use the signature object sender, EventArgs e. This pattern gives subscribers both the event source and any attached payload while keeping publisher and listener loosely coupled. Understanding why this signature exists helps you design clear event contracts in desktop apps, services, and reusable libraries.

Core Sections

Why the Signature Uses sender and EventArgs

sender is the object that raised the event. It lets one handler process events from multiple publishers and branch on source when needed.

EventArgs is a payload object. When no payload is needed, EventArgs.Empty communicates that explicitly without allocating new objects.

Basic event declaration and raise pattern:

csharp
1public class JobRunner
2{
3    public event EventHandler? Completed;
4
5    public void Run()
6    {
7        // work
8        Completed?.Invoke(this, EventArgs.Empty);
9    }
10}

Subscribers receive both parameters and can decide how much they care about each.

Creating Strongly Typed Event Data

Real systems usually need payload fields, so define custom event argument classes derived from EventArgs.

csharp
1public sealed class FileProcessedEventArgs : EventArgs
2{
3    public string FileName { get; }
4    public int RecordCount { get; }
5
6    public FileProcessedEventArgs(string fileName, int recordCount)
7    {
8        FileName = fileName;
9        RecordCount = recordCount;
10    }
11}
12
13public class ImportService
14{
15    public event EventHandler<FileProcessedEventArgs>? FileProcessed;
16
17    public void Process(string file)
18    {
19        int records = 120;
20        FileProcessed?.Invoke(this, new FileProcessedEventArgs(file, records));
21    }
22}

Now subscribers get compile time access to FileName and RecordCount without casting from untyped state.

Subscribing, Unsubscribing, and Lifetime Safety

Handlers are attached with += and removed with -=. In long lived applications, forgetting to unsubscribe can keep objects alive unexpectedly.

csharp
1var importer = new ImportService();
2
3EventHandler<FileProcessedEventArgs> handler = (sender, e) =>
4{
5    Console.WriteLine($"{e.FileName}: {e.RecordCount}");
6};
7
8importer.FileProcessed += handler;
9importer.Process("customers.csv");
10importer.FileProcessed -= handler;

If publisher lifetime exceeds subscriber lifetime, always remove handlers during disposal or shutdown hooks.

Interpreting sender Safely in Handlers

Do not assume sender is always a specific type unless the event contract guarantees it. Use pattern matching for safety.

csharp
1private static void OnCompleted(object? sender, EventArgs e)
2{
3    if (sender is JobRunner runner)
4    {
5        Console.WriteLine("Completed event from JobRunner");
6    }
7    else
8    {
9        Console.WriteLine("Completed event from unknown source");
10    }
11}

This keeps handlers robust when reused across contexts.

Threading and Async Boundaries

Events run on the thread that raises them. In UI frameworks, background threads cannot update controls directly, so handlers often need dispatch back to the UI thread.

For service code, avoid blocking handlers that run on critical worker threads. If heavy processing is required, queue work and return quickly.

csharp
1public event EventHandler? Tick;
2
3public void RaiseTick()
4{
5    Tick?.Invoke(this, EventArgs.Empty);
6    // handlers should stay lightweight here
7}

For async workflows, event handlers can call async methods, but keep exception handling explicit because event invocation chains can hide failures.

Design Guidelines for Maintainable Events

Events are best for notifications, not command execution. Keep payloads focused on what changed, avoid mutable shared objects, and document ordering expectations.

Good event design checklist:

  1. Name event by past tense action, for example Completed or Saved.
  2. Keep payload small and immutable.
  3. Define clear publisher ownership and unsubscription policy.
  4. Avoid cross layer control flow hidden behind events.

These rules make event driven systems easier to test and reason about.

Common Pitfalls

  • Casting sender blindly without type checks.
  • Using events as hidden command channels instead of notifications.
  • Forgetting to unsubscribe handlers from long lived publishers.
  • Passing mutable global state through event payloads.
  • Running expensive logic directly inside publisher thread handlers.

Summary

  • sender identifies the publisher instance that raised the event.
  • EventArgs carries payload, or EventArgs.Empty when no payload is needed.
  • Use EventHandler<TEventArgs> for strongly typed event data.
  • Manage handler lifetimes carefully to avoid retention bugs.
  • Keep event contracts simple, explicit, and notification focused.

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.