Func<T> and Action<T> arrived with C# 3.0 and quickly became the standard delegate shapes for modern C#. Func represents behavior that returns a value, while Action represents behavior that only performs work.
Why it matters
- Reduces custom delegate boilerplate in APIs and utility methods.
- Pairs naturally with lambdas and LINQ-style composition.
- Makes behavior-first design easier by passing functions as arguments.
Cautions
Prefer named methods when a delegate body becomes long or hard to scan. Keep delegate signatures clear and avoid deeply nested lambda chains that obscure intent.
Use Func<T> to pass calculations
Func delegates are ideal when behavior should be injected and a value returned.
Valid since C# 3.0
using System;
class Program
{
static int Apply(int left, int right, Func<int, int, int> operation)
{
return operation(left, right);
}
static void Main()
{
int sum = Apply(10, 5, (x, y) => x + y);
int product = Apply(10, 5, (x, y) => x * y);
Console.WriteLine(sum); // 15
Console.WriteLine(product); // 50
}
}
Use Action<T> for side-effect steps
Action delegates make it easy to pass work that does not return a value.
Valid since C# 3.0
using System;
class Program
{
static void ForEachName(string[] names, Action<string> handleName)
{
foreach (string name in names)
{
handleName(name);
}
}
static void Main()
{
string[] names = { "Ana", "Lee", "Sam" };
ForEachName(names, name => Console.WriteLine("Hello, " + name));
}
}