Lambda expressions C# 3.0 are powerful but had limitations compared to regular methods. They couldn't have attributes applied, couldn't specify explicit return types, and required explicit delegate types when assigned to variables.
C# 10.0 brings lambdas closer to methods by allowing attributes, explicit return types, and natural type inference, making them more flexible and reducing the need for explicit delegate declarations.
Code
csharp
// Attributes on lambdas
var validate = [return: NotNull] (string? s) => s ?? throw new ArgumentNullException(nameof(s));
var lambda = [SomeAttribute] (int x) => x * 2;
// Explicit return types
var parse = int (string s) => int.Parse(s);
var getValue = ref int () => ref _field;
// Natural type inference
var add = (int a, int b) => a + b; // Inferred as Func<int, int, int>
var greet = () => "Hello"; // Inferred as Func<string>
var print = (string s) => Console.WriteLine(s); // Inferred as Action<string>
// Natural type also works when the target is Delegate or object
Delegate handler = () => "Hello"; // Func<string>, as used by minimal APIs
// Explicit return type when the body has no natural type
var choose = object (bool b) => b ? 1 : "string";csharp
// No attributes on lambdas, so you had to use named methods
[SomeAttribute]
int ApplyTransform(int x) => x * 2;
Func<int, int> lambda = ApplyTransform;
// No explicit return types
Func<string, int> parse = s => int.Parse(s);
// No ref returns from lambdas at all
// Required explicit delegate type
Func<int, int, int> add = (a, b) => a + b;
Func<string> greet = () => "Hello";
Action<string> print = s => Console.WriteLine(s);
// Had to cast to a specific delegate type first
Delegate handler = (Func<string>)(() => "Hello");
// Return type had to come from the delegate type
Func<bool, object> choose = b => b ? 1 : "string";Notes
- Attributes: Apply attributes to lambda parameters, the lambda itself, or the return value (
[return: ...]); the parameter list must be in parentheses - Explicit return types: Specify return type before parameters:
returnType (params) => expression - Natural type: The compiler infers
Func<>orAction<>delegate types from lambda signatures, or synthesizes a delegate type when none fits (such as forrefreturns) - Ref returns: Lambdas can now return ref values with explicit return type syntax
- Method groups also gain a natural type, so
var read = Console.Read;works, later improved by method group natural type improvements C# 13.0 - Extended further by default lambda parameters C# 12.0