delegate keyword vs. lambda notation
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In C#, delegates and lambdas are closely related, but they are not the same thing. A delegate is a type that represents a callable method signature, while a lambda is a compact way to create a function value that can be assigned to a delegate or expression tree. The confusion usually comes from the fact that lambdas are often used where delegates are expected.
What a Delegate Actually Is
A delegate is a type-safe function signature. It defines what kind of method can be stored or invoked.
Here, MathOperation is the delegate type. It says any compatible method must take two integers and return one integer.
What a Lambda Actually Is
A lambda expression is a concise way to write an anonymous function.
The lambda itself is not the delegate type. Instead, it is converted to a compatible target such as a Func that takes two integers and returns one integer, or a custom delegate type.
The Older Anonymous Method Syntax
Before lambdas became the preferred style, C# had anonymous methods written with the delegate keyword.
This form still works, but lambdas are usually shorter and more readable.
delegate Keyword Has Two Different Roles
This is where many explanations become muddy. The delegate keyword appears in two related but different places:
- to declare a delegate type
- to create an anonymous method
Delegate type declaration:
Anonymous method:
Lambda syntax is the newer way to express the second case, not the first.
When Lambdas Are Usually Better
Lambdas are usually preferred for short inline behavior, especially with LINQ, events, and callbacks.
This is far cleaner than writing a separate named method or an older anonymous method just to express a tiny predicate.
When a Named Delegate Type Still Helps
Custom delegate types can still be useful when the callable concept has domain meaning. A named delegate can make an API more self-documenting than a raw Func or Action.
That communicates intent more clearly than a Func taking a string and returning a boolean in some codebases, especially public libraries.
Captured Variables Work with Lambdas and Anonymous Methods
Both lambdas and anonymous methods can close over local variables.
This captured-variable behavior is powerful, but it also means the anonymous function may outlive the local scope that created it, which can surprise developers when debugging state changes.
Lambdas Can Also Become Expression Trees
One extra reason lambdas matter in .NET is that some APIs do not want a delegate at runtime. They want an expression tree that can be inspected and translated.
Example with LINQ providers:
That is beyond plain delegate invocation and is one reason lambdas are more fundamental in modern C# style than the older anonymous delegate syntax.
Practical Rule of Thumb
Use a lambda when you need inline behavior. Use a named delegate type when the callable itself has domain meaning. Use the older anonymous delegate syntax only when there is a specific language reason or you are maintaining existing code that already uses it.
In modern C# application code, lambdas dominate because they are concise and integrate naturally with framework APIs.
Common Pitfalls
- Saying delegates and lambdas are the same thing when one is a type and the other is syntax.
- Forgetting that
delegatecan mean either type declaration or anonymous method syntax. - Using a custom delegate type where
FuncorActionwould be simpler. - Ignoring variable capture behavior when lambdas depend on changing outer state.
- Choosing the older anonymous method form when a lambda would be clearer.
Summary
- A delegate is a callable type definition.
- A lambda is a compact anonymous function syntax that can be converted to a delegate or expression tree.
- The
delegatekeyword is used both for delegate type declarations and for older anonymous method syntax. - Lambdas are usually the best choice for inline callbacks and LINQ.
- Named delegate types still make sense when the callable concept has real semantic meaning in the API.

