4. Delegates, Events & Lambdas


Evolution Timeline

C# 1.0 (2002)          C# 2.0 (2005)              C# 3.0 (2007)
    ↓                       ↓                          ↓
Delegates    →    Anonymous Methods    →    Lambda Expressions
(Verbose)         (Better)                   (Best - Modern)

1. Delegates (C# 1.0)

What are Delegates?

Delegates = Type-safe function pointers

Definition: A delegate is a type that represents references to methods with a particular parameter list and return type.

Think of it as: A variable that holds a method.

// Without delegate (direct call)
int result = Add(5, 3);

// With delegate (indirect call)
Operation operation = Add;
int result = operation(5, 3);

Declaring Delegates

Instantiating Delegates

Invoking Delegates

Multicast Delegates

Multicast delegates can reference multiple methods.

Important Notes:

  • Methods are invoked in the order they were added

  • If delegate returns a value, only the last method's return value is returned

  • If any method throws an exception, remaining methods are not called

Delegate Variance (Covariance & Contravariance)

Covariance - Return type can be more derived

Contravariance - Parameter type can be less derived


2. Built-in Generic Delegates

Action<T> - No Return Value (C# 3.0+)

Purpose: Encapsulates a method that takes 0-16 parameters and returns void.

Common Use Cases:

Func<T, TResult> - With Return Value (C# 3.0+)

Purpose: Encapsulates a method that takes 0-16 parameters and returns a value.

Common Use Cases:

Predicate<T> - Returns bool (C# 2.0+)

Purpose: Represents a method that takes one parameter and returns bool.

Comparison: Action vs Func vs Predicate

Type
Parameters
Return Type
Example

Action

0-16

void

Action<string> print = s => Console.WriteLine(s);

Func

0-16

Any type (last param)

Func<int, int> square = x => x * x;

Predicate

1

bool

Predicate<int> isEven = x => x % 2 == 0;

When to use:

  • Action - Side effects, no return value needed

  • Func - Transformations, calculations, return value needed

  • Predicate - Testing/filtering (bool result) - mostly legacy, use Func<T, bool>


3. Events (C# 1.0)

What are Events?

Events = Special delegates that implement the publisher-subscriber pattern.

Purpose: Allow a class to notify other classes when something happens.

Event vs Delegate

EventHandler and EventHandler<T>

Basic Event Pattern

Custom EventArgs

Multiple Subscribers

Event Accessors (add/remove)


4. Anonymous Methods (C# 2.0)

Anonymous methods allow you to define methods inline without a name.

Syntax

Omitting Parameters

Captured Variables (Closures)

Limitations

  • More verbose than lambda expressions

  • Cannot omit parameter types

  • Cannot be converted to expression trees

  • Replaced by lambdas in C# 3.0+


5. Lambda Expressions (C# 3.0+)

Lambda expressions are a concise way to write anonymous methods.

Expression Lambda

Single expression, implicit return

Statement Lambda

Multiple statements, explicit return

Type Inference

No Parameters

Discards (C# 9.0+)

Lambda Improvements (C# 10.0+)

Natural Types

Attributes on Lambdas

Lambda Optional Parameters (C# 12.0+)

Evolution: Delegate → Anonymous Method → Lambda

Always prefer lambdas in modern C#!


6. Expression Trees (C# 3.0+)

What are Expression Trees?

Expression trees represent code as data structures.

Why Use Expression Trees?

LINQ to SQL/Entities uses them to translate C# to SQL:

Building Expression Trees

Examining Expression Trees


7. Closures

What are Closures?

Closure = Lambda/delegate that captures variables from outer scope.

How Closures Work

Lifetime Extension

Common Pitfall: Loop Variable Capture


8. Func and Action in Practice

Higher-Order Functions

Functions that take functions as parameters

Callbacks

Method Chaining

LINQ Integration


Common Patterns

Observer Pattern (Events)

Command Pattern (Action)

Strategy Pattern (Func)

Factory Pattern (Func)


Comparison Tables

Delegate Evolution

Feature
Delegate (C# 1.0)
Anonymous Method (C# 2.0)
Lambda (C# 3.0+)

Syntax

Named method required

delegate(params) { }

(params) => expr

Verbosity

Most verbose

Verbose

Concise

Type inference

No

No

Yes

Expression trees

No

No

Yes

Modern usage

Legacy

Rare

✅ Preferred

Built-in Delegates

Delegate
Parameters
Return
Example

Action

0-16

void

Action<string> print = s => Console.WriteLine(s);

Func

0-16

Last type param

Func<int, int> square = x => x * x;

Predicate

1

bool

Predicate<int> isEven = x => x % 2 == 0;

Event vs Delegate

Feature
Delegate
Event

Assignment

Can reassign (=)

Can only add/remove (+=, -=)

Invocation

Can invoke from anywhere

Can only invoke from declaring class

Encapsulation

Poor

Excellent

Use case

Callbacks

Notifications


Lambda Syntax Reference


Common Pitfalls

1. Event Memory Leaks

2. Loop Variable Capture (Before C# 5.0)

3. Multicast Delegate Return Values

4. Invoking Null Delegates


Best Practices

1. Use Lambda Expressions

2. Use Built-in Delegates

3. Use Events for Notifications

4. Always Unsubscribe from Events

5. Use Expression Lambda for Simple Operations

6. Be Careful with Closures

7. Use Null-Conditional for Events


Quick Reference Summary

Delegates

  • Type-safe function pointers

  • Can reference multiple methods (multicast)

  • Use Action/Func instead of custom delegates

Events

  • Special delegates for publisher-subscriber pattern

  • Encapsulated (can't reassign or invoke externally)

  • Always unsubscribe to prevent memory leaks

Lambda Expressions

  • Concise way to write anonymous methods

  • Syntax: (params) => expression or (params) => { statements }

  • Preferred over anonymous methods and named methods (for simple cases)

Closures

  • Lambdas/delegates that capture outer variables

  • Be careful with loop variables

  • Variables are captured by reference, not value

Common Delegates

  • Action - No return value

  • Func - Returns value

  • Predicate - Returns bool (legacy, use Func<T, bool>)


Guide Complete! This covers all aspects of delegates, events, and functional programming in C#. Master these concepts and you'll understand how LINQ works under the hood! 📘

Last updated