← Home
.NETOOP and C# basicsReported by candidates

What are delegates, Func and Action, and events? Where have you used them?

Asked in first technical rounds at Infosys (three reports), Wipro, Cognizant, Deloitte and Mindfire; latest report October 2026.

Say this first · about 30 seconds
Make it yours · Navistar collections queue (invented example)
The code, simplified

Invented to show the shape, in C#. Tap Next to walk account T-881 through the rules.

Navistar.sln · where these 2 files sit
  • Jobs/
Diagram · step 1The job stores three rules as delegates and hands the list to the queue.
MorningCallJob.cs · line 1 · 1 of 4Called at 07:00 by the morning job.

Fix later in your repo The rule list is built in code; a later step could load rule settings from config.

Say it out loud, then check

Show the 30-second answer
  • A delegate is a type-safe reference to a method. Type-safe means the compiler only lets in methods with the right parameters and return type. You can store a method in a variable, pass it to another method, and call it later.
  • Func and Action are the built-in delegate types: Func returns a value, Action returns nothing. I use Func every day in LINQ, for example a Where filter.
  • An event is a delegate the owning class wraps, so outside code can only subscribe or unsubscribe, and only the owner can raise it.
  • In our contract service, activation raises an Activated event, and the welcome mail and ledger posting subscribe to it. The rule: when the publisher lives longer than the subscriber, unsubscribe, or the publisher keeps it in memory and keeps calling it.
Check your answer: tick what you said

You said 0 of 9

Then add your example: Navistar collections queue (invented example)
  • Situation: at Navistar Financial the collections team decides each morning which truck accounts get a phone call. Their rules kept changing: over 30 days late, owing more than 500, not in bankruptcy, and new ones every month.
  • What I did: I stored each rule as a in a list. runs every rule on an account and calls only if all say yes. A new rule is one line where the list is built.
  • Result: the queue class stopped changing every sprint. Each rule is a lambda you can test on its own, and the team could read the list.
  • What I'd say: I used delegates to make rules data, not code paths. Once a rule needed a database lookup, I'd move it behind an interface so DI could build it.

See it

1/7Before: activation calls the mailer and the ledger itself, by name.

In plain words

The senior answer · about 2 minutes
What they are
  • A delegate is a type that describes a method's shape: what it takes and what it returns. A variable of that type holds a method, plus, for an instance method, the object it should run on (a static method has none). The compiler checks the shape, so you can't put a method with the wrong parameters in it. That's what type-safe means here.
  • I almost never declare my own type now. covers every method that returns something, covers every method that returns nothing, and is an older one for yes or no checks. The custom keyword still shows up in old code and in some framework types like .
  • Every delegate is multicast. += adds a method to its invocation list, which is just the list of methods it will call. Calling the delegate runs each one in order, on the caller's thread, one after another.
Why events exist
  • If a class exposed a public delegate field, any outside code could set it to null and wipe every subscriber, or call it and pretend the thing happened. The keyword closes both holes: from outside you can only += and -=; only the owning class can raise it.
  • The point is decoupling. The class that activates a contract doesn't know who cares. Mail, the ledger and later an SMS sender subscribe themselves, and the activation code never changes when a new reaction is added.
  • The standard shape is : the sender, and an object carrying the data. I raise it with ?.Invoke, because an event with no subscribers is null.
Where it goes wrong
  • Leaks. The publisher's list holds a reference to every subscriber, so a short-lived object that subscribes to a long-lived publisher can't be freed, and its handler keeps running. Whoever subscribes must unsubscribe, usually in . The full memory story is on the card.
  • One handler throws and the rest don't run, because they run one after another in the same call. And an handler can't be awaited, so its exception can crash the process. Keep handlers small and catch inside them.
  • With a multicast , only the last method's return value comes back. If you need every answer, loop over .
How I choose in a real app
  • Inside one process and one object lifetime, an event is fine. In an ASP.NET Core API, where objects live per request, I'd rather inject a list of handlers through DI, for example , because DI controls their lifetime and nothing has to unsubscribe.
  • Across services, or when the reaction must survive a crash, it's a message on Azure , not a C# event. A C# event lives in memory; if the process restarts, it's gone.

All in one flow

Coming Not written yet: the card pass adds it.

The story

  1. Before

    At BMW FS a contract goes live in the nightly . When it does, the customer gets a welcome pack and the ledger gets a posting. The first version of called and directly, by name.

  2. Why it had to change

    Then UDC Finance asked for an SMS on activation. To add it, someone had to open the activation code, add a third call, retest activation for all three clients and redeploy it. The class that makes a contract live was changing for a reason that has nothing to do with going live.

  3. How it works now

    The activator now owns an event, . An event holds a list of delegates; a delegate is one method plus the object to run it on. The mailer, the ledger and the SMS sender each add themselves with +=. When a contract goes live, the activator raises the event once and every method in the list runs, in order. The diagram above walks it.

  4. What happens next

    Adding the SMS was one new class and one += line in Program.cs. didn't change, so it didn't need retesting. Removing a reaction is one -=.

  5. What we gained

    The publisher knows nothing about its subscribers. Each reaction is its own small class with its own test. The price: someone must remember to unsubscribe, which is exactly the bug in the try-first exercise below.

In the lending API

The publisher: it owns the event and raises it. It never names who listens.

Only the key lines are shown; Deep walks the whole file.

Lending.sln · where this file sits
  • src/Domain/Contracts/
⋯ 8 lines in Deep
ContractActivator.cs · line 3 · 1 of 3: outside code may only += and -=. It can't set the list to null or raise it.

The code, file by file

Contract activation in the lending API's nightly . Tap Next to walk the diagram with the code.

Lending.sln · where these 5 files sit
  • src/
    • Worker/
      • Notifications/
    • Domain/Contracts/
    • Application/Billing/
Diagram · step 1Before: activation calls the mailer and the ledger itself, by name.
Program.cs · line 1 · 1 of 3The publisher. In the real DI builds these as singletons; plain here so you can trace where each object comes from.

What they ask next

The follow-ups interviews really ask. Answer out loud, then tap to check.

Follow-up tree

Answer, then open the next level. That is the order an interviewer digs in.

Reporteda candidate was asked Intervieweran interviewer asks it

Production bugs, and how to tell them

Each one: what you see, why, the fix in code, and the line to say.

Production incident

Not on this card A basic concept card: its production story is the try-first bug here and the event leak on the GC and memory card.

Traps

Traps

What should you say instead? Tap to check.

Live coding

Easy first, then harder. Set a timer and type it before you look.

Task 1

Reportedeasy · 15 minutes

Write code that shows delegates and events: a publisher with an event, two subscribers, and one subscriber leaving. Use a somewhere for a calculation.

Global Quest Solutions: write code demonstrating events and delegates
Stuck? Hints
  1. Declare the event with and raise it with ?.Invoke(this, args).
  2. Subscribe a named method, not a lambda, so you can unsubscribe it.
  3. Where does a fit? A fee rule passed into a method.
Show a solution
Lending.sln · where this file sits
Program.cs · line 7 · 1 of 4A for a real calculation: monthly amount plus a service fee.
What the interviewer checks
  • keyword, not a public delegate field, and you can say why.
  • Raised with ?.Invoke, so no subscribers is not a crash.
  • Event data in a class with read-only properties.
  • -= used, and the output proves the removed subscriber no longer runs.
  • A used for a real calculation, not just declared.
  • Senior extra: says where it would be , and when it would be a queue instead.
With AI tools

Copilot writes delegates well, but two of its habits show up in review. It subscribes with a lambda (x.Changed += (s, e) => ...) and never unsubscribes, and it sometimes "fixes" an unsubscribe by writing -= with a second, identical lambda, which removes nothing. When I review AI code with events I check three things: every += has a matching -= or a reason it lives forever, handlers are named methods, and no handler is missing its try-catch.

Glossary: every name, one line each →

My notes

Paste the NOTES block from your doubt chat here. The grader never reads notes; the coach reads "Still unclear".

Read moreWhere it was asked