C# Programming Tutorial 0/45 lessons ~6 min read Lesson 33

    Delegates

    A delegate is a type-safe function pointer — references methods matching a signature.

    Course progress0%
    Focus
    10 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    A delegate is a type-safe function pointer — references methods matching a signature. Action, Func, and Predicate built-ins cover common cases. Delegates enable callbacks, LINQ, and event foundations.

    Multicast delegates combine multiple handlers with +=. Interviewers ask delegate vs interface callback and memory leaks from long-lived delegate references.

    The story

    An integration service calls an external credit bureau API that occasionally times out. Instead of duplicating retry loops everywhere, a RetryExecutor accepts any async operation as a Func<Task<T>> delegate and retries it three times with a delay — the same utility works for HTTP calls, database queries, or file uploads.

    Understanding the topic

    Key concepts

    • delegate keyword declares method signature type.
    • Action no return; Func last type param return; Predicate bool.
    • Multicast += and -= combine invocations.
    • Null delegate invoke throws NullReferenceException.
    • Method group conversion: DoWork without parentheses.
    • Func used extensively in LINQ lambdas.

    Step-by-step explanation

    1. Declare delegate type or use built-in Action/Func.
    2. Assign method or lambda matching signature.
    3. Invoke with delegate(args) or delegate.Invoke(args).
    4. Multicast calls all subscribers in order.
    5. Covariance/contravariance on delegate parameters.
    6. Pass delegate to strategy methods.

    Practical code example

    Retry executor using Func delegate:

    csharp
    namespace TechLearningPro.Delegates;
    public static class RetryExecutor
    {
    public static async Task<T> ExecuteAsync<T>(
    Func<Task<T>> operation,
    int maxAttempts,
    TimeSpan delay)
    {
    for (var attempt = 1; attempt <= maxAttempts; attempt++)
    {
    try
    {
    return await operation();
    }
    catch when (attempt < maxAttempts)
    {
    await Task.Delay(delay);
    }
    }
    throw new InvalidOperationException("Unreachable");
    }
    }
    // Usage: await RetryExecutor.ExecuteAsync(() => http.GetStringAsync(url), 3, TimeSpan.FromSeconds(1));

    Line-by-line code explanation

    • ExecuteAsync<T>(Func<Task<T>> operation, ...) accepts any async lambda matching the delegate signature.
    • for (var attempt = 1; attempt <= maxAttempts; attempt++) loops through retry attempts.
    • try { return await operation(); } invokes the caller-supplied delegate and returns on success.
    • catch when (attempt < maxAttempts) catches failures only when retries remain.
    • await Task.Delay(delay) waits before the next attempt — backoff can be added here.
    • throw new InvalidOperationException("Unreachable") satisfies the compiler after the loop — should never run.
    • Func<Task<T>> is the type-safe function pointer that makes the executor reusable.
    • () => http.GetStringAsync(url) is an example lambda passed as the operation delegate.

    Key takeaway: Func> accepts any async lambda — classic delegate abstraction without interface boilerplate.

    Real-world use

    Where you'll use this in production

    • LINQ Where/Select predicate parameters.
    • Timer callbacks and ThreadPool.QueueUserWorkItem.
    • Plugin hooks passing Action on lifecycle.
    • Comparison delegates for Sort.

    Best practices

    • Prefer Func/Action over custom delegate types unless public API.
    • Null-check before invoke or use ?.Invoke.
    • Unsubscribe multicast to prevent leaks.
    • Use interface when multiple related methods needed.
    • Document thread context expectations on invoke.

    Common mistakes

    • Invoking null delegate.
    • Multicast exception stops remaining handlers.
    • Capturing large object in long-lived delegate.
    • Confusing delegate type with invoked method return.

    Advanced interview questions

    Q1BeginnerDelegate vs interface?
    Delegate single method callback; interface multi-method contract.
    Q2BeginnerFunc vs Action?
    Func has return type; Action void return.
    Q3IntermediateMulticast delegate?
    Combines multiple methods; += adds handler.
    Q4IntermediateCovariance on Func?
    Func assignable to Func return covariant.
    Q5AdvancedImplement retry with exponential backoff via delegate.
    Func> operation; loop with catch filter transient; Delay 2^attempt; optional onRetry Action.

    Summary

    Delegates reference methods with type-safe signatures. Action, Func, Predicate cover common scenarios. Foundation for events and LINQ lambdas. Multicast enables multiple subscribers. Next: events on top of delegates.

    Ready to mark this lesson complete?Track your journey across the entire course.