Func<T> and Action<T>

C# 3.0 NETFx 3.5

Published Updated Author Jeffrey T. Fritz Reading time

Use built-in generic delegate types to pass behavior without defining one-off delegate types.

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));
    }
}

Learn more

Delegate types (Microsoft Learn)