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
C#
// Attributes on lambdas
var lambda = [SomeAttribute] (int x) => x * 2;
Action<string> logger = [Conditional("DEBUG")] (msg) => Console.WriteLine(msg);
// 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>
// Can assign to var without explicit delegate type
var numbers = new[] { 1, 2, 3, 4, 5 };
var doubled = numbers.Select((int x) => x * 2); // Type inference works better
// Return type helps with overload resolution
var choose = object (bool b) => b ? 1 : "string";
C#
// No attributes on lambdas - had to use named methods
int ApplyTransform(int x)
{
[SomeAttribute]
return 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 specify delegate type explicitly
var numbers = new[] { 1, 2, 3, 4, 5 };
var doubled = numbers.Select((Func<int, int>)(x => x * 2));
// Ambiguous without explicit type
Func<bool, object> choose = b => b ? 1 : "string";
Notes
- Attributes: Apply attributes to lambda parameters, the lambda itself, or the return value
- Explicit return types: Specify return type before parameters:
returnType (params) => expression
- Natural type: The compiler infers
Func<>
orAction<>
delegate types from lambda signatures - Ref returns: Lambdas can now return ref values with explicit return type syntax
- Natural type inference allows assigning lambdas to
var
without losing type information - Explicit return types help with overload resolution and clarify intent
- These features make lambdas behave more like regular methods