Skip to Content
Course content

250: Common C# Interview Questions on Delegates vs Events

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've seen this happen more times than I can count in code reviews. A developer wants to implement a notification system, so they use a public delegate. It seems to work perfectly during the first five minutes of testing, but then it creates a nightmare for maintainability and stability. Let's look at a realistic example of where this goes sideways.

public class TemperatureSensor 
{
    // A public delegate to notify listeners when the temp changes
    public Action<float> OnTemperatureChanged;

    public void UpdateTemperature(float newTemp) 
    {
        Console.WriteLine($"Sensor reading: {newTemp}°C");
        OnTemperatureChanged?.Invoke(newTemp);
    }
}

public class Program 
{
    public static void Main() 
    {
        var sensor = new TemperatureSensor();
        
        // Subscriber 1: The Logger
        sensor.OnTemperatureChanged += (t) => Console.WriteLine($"Log: Temp is {t}");
        
        // Subscriber 2: The Alarm (but they made a mistake)
        // Instead of +=, they used =
        sensor.OnTemperatureChanged = (t) => {
            if (t > 100) Console.WriteLine("ALARM! OVERHEATING!");
        };

        sensor.UpdateTemperature(110); 
        // Wait... where did the Logger go?
    }
}

The Accidental Wipeout and the Security Hole

If you run that code, you'll notice the "Log: Temp is 110" message completely disappeared. Because OnTemperatureChanged is just a public delegate field, any piece of code anywhere in the application can use the assignment operator (=) to wipe out every other subscriber. In a large system, debugging why a specific listener stopped firing is a total waste of your afternoon.

But there's a worse problem here: encapsulation. Because that delegate is public, any class can call sensor.OnTemperatureChanged.Invoke(999). Imagine if a UI component accidentally "triggered" the sensor's notification logic, tricking the rest of the system into thinking the temperature just spiked, even though the hardware sensor never actually read that value. The class has lost control over its own internal state.

Enforcing Encapsulation with the Event Keyword

To fix this, we use the event keyword. Think of an event as a protective wrapper around a delegate. It restricts the "outside world" to only two operations: subscribing (+=) and unsubscribing (-=). It prevents anyone from overwriting the list or triggering the event from outside the class.

public class TemperatureSensor 
{
    // Adding the 'event' keyword changes the access rules
    public event Action<float> OnTemperatureChanged;

    public void UpdateTemperature(float newTemp) 
    {
        Console.WriteLine($"Sensor reading: {newTemp}°C");
        // This is still allowed because we are inside the TemperatureSensor class
        OnTemperatureChanged?.Invoke(newTemp);
    }
}

public class Program 
{
    public static void Main() 
    {
        var sensor = new TemperatureSensor();
        sensor.OnTemperatureChanged += (t) => Console.WriteLine($"Log: Temp is {t}");
        
        // THIS WILL NOW CAUSE A COMPILE-TIME ERROR:
        // sensor.OnTemperatureChanged = (t) => { ... }; 
        
        // THIS WILL ALSO CAUSE A COMPILE-TIME ERROR:
        // sensor.OnTemperatureChanged.Invoke(100); 
    }
}

Now, the compiler protects us. The event keyword ensures that the TemperatureSensor is the only entity that can decide when the notification happens, and it ensures that subscribers can't accidentally kick each other off the list.

Winning the "Delegates vs Events" Interview Question

When an interviewer asks you the difference between a delegate and an event, they aren't just checking if you know the syntax. They are checking if you understand encapsulation. If you just say "events use delegates," you're giving a textbook answer that doesn't impress anyone.

I recommend framing your answer around these three specific points:

  • Ownership: A delegate is a type; an event is a modifier. An event is essentially a delegate that is encapsulated so that only the declaring class can invoke it.
  • Safety: Events prevent external classes from using the assignment operator (=), which would otherwise overwrite all existing subscriptions.
  • Intent: Using an event signals to other developers that "this is a notification you can listen to, but you are not allowed to trigger it yourself."



📋 Practical Task

Fixing the Broken Stock Ticker Notification System

You have been handed a StockTicker class that is causing intermittent bugs in a trading app. Currently, it uses a public delegate, and a junior developer has accidentally written code that triggers fake price updates from the UI layer, causing the trading bot to make bad trades.

Your Task:

  1. Modify the StockTicker class to use an event instead of a public delegate to ensure that only the StockTicker can trigger notifications.
  2. Ensure that the UpdatePrice method still triggers the notification.
  3. In the Main method, attempt to call ticker.OnPriceChanged.Invoke(...) and verify that the code no longer compiles (you can comment this line out after verifying the error).
using System;

public class StockTicker
{
    // TODO: Change this from a public delegate to an event
    public Action<string, decimal> OnPriceChanged;

    public void UpdatePrice(string symbol, decimal price)
    {
        Console.WriteLine($"Updating {symbol} to {price}...");
        OnPriceChanged?.Invoke(symbol, price);
    }
}

public class Program
{
    public static void Main()
    {
        var ticker = new StockTicker();

        ticker.OnPriceChanged += (symbol, price) => 
            Console.WriteLine($"Notification: {symbol} is now {price}");

        ticker.UpdatePrice("MSFT", 420.50m);

        // TODO: This line should be blocked by the compiler after your changes
        // ticker.OnPriceChanged.Invoke("MSFT", 1000.00m); 
    }
}
Rating
0 0

There are no comments for now.

to be the first to leave a comment.