A callback in C# is a mechanism for executing a method (or function) when a certain action is complete or a certain event occurs. It allows you to pass a reference to a method as an argument to another method, which can then call the referenced method at the appropriate time.

Callbacks can be implemented in C# using delegates, anonymous methods, or lambda expressions. They are commonly used to achieve asynchronous programming, event handling, or modular code design.

How Callbacks Work in C#

  1. Delegate-based Callbacks: A delegate is a type that represents a method signature. You can use it to reference and invoke methods that match the signature.

    // Delegate declaration
    public delegate void CallbackDelegate(string message);
    
    public class CallbackExample
    {
        public void PerformAction(CallbackDelegate callback)
        {
            // Simulating some work
            Console.WriteLine("Performing an action...");
            // Invoking the callback
            callback("Action completed!");
        }
    }
    
    public class Program
    {
        public static void Main(string[] args)
        {
            var example = new CallbackExample();
            example.PerformAction(message => Console.WriteLine(message)); // Using a lambda expression as a callback
        }
    }
    
  2. Event-based Callbacks: Events are a higher-level abstraction that use delegates under the hood. They are typically used for signaling when something happens.

    public class EventExample
    {
        public event Action<string> OnActionCompleted;
    
        public void PerformAction()
        {
            Console.WriteLine("Performing an action...");
            OnActionCompleted?.Invoke("Action completed!");
        }
    }
    
    public class Program
    {
        public static void Main(string[] args)
        {
            var example = new EventExample();
            example.OnActionCompleted += message => Console.WriteLine(message);
            example.PerformAction();
        }
    }
    
  3. Task-based Callbacks: With modern asynchronous programming, callbacks are often represented using Task and async/await.

    public class AsyncExample
    {
        public async Task PerformActionAsync(Func<string, Task> callback)
        {
            Console.WriteLine("Performing an action...");
            await Task.Delay(1000); // Simulating work
            await callback("Action completed!");
        }
    }
    
    public class Program
    {
        public static async Task Main(string[] args)
        {
            var example = new AsyncExample();
            await example.PerformActionAsync(async message =>
            {
                Console.WriteLine(message);
                await Task.CompletedTask;
            });
        }
    }
    

Typical Use Cases of Callbacks

  1. Asynchronous Programming: Callbacks are often used in asynchronous operations to execute a method after a long-running task (e.g., file I/O, web requests, or database queries) completes.

  2. Event Handling: In frameworks like WPF, WinForms, or Unity, callbacks are used to handle user interface events, such as button clicks or mouse movements.

  3. Dependency Injection: Callbacks allow injecting custom behavior into a generic method or class without tightly coupling the logic.

  4. Extensibility: Callbacks enable creating flexible and reusable APIs, where the library user can supply their custom logic as a callback.

  5. Functional Programming: Callbacks can make it easier to perform operations on collections (e.g., LINQ queries) or implement design patterns like strategy and observer patterns.

Callbacks in C# provide a powerful way to decouple components and allow for dynamic behavior in applications.