Skip to content

Lambda improvements C# 10.0code reduction

Add attributes, explicit return types, and natural type inference to lambdas.

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<> or Action<> delegate types from lambda signatures, or synthesizes a delegate type when none fits (such as for ref returns)
  • 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

More information ​

Powered by Intracia