In C#, delegates like Action and Func allow you to treat behavior as data — meaning you can pass methods around like variables.

This concept is powerful and opens doors to cleaner, more flexible, and decoupled code.

In this article, we’ll explore:

  1. What Action and Func are
  2. How to use them effectively
  3. Real-world examples using design patterns like Strategy and Command

What Are Action and Func in C#?

Action Delegate
Represents a method that returns void.
Can take 0 to 16 input parameters.

Action<string> greet = name => Console.WriteLine($"Hello, {name}!");
greet("Alice"); // Output: Hello, Alice!

Func Delegate
Represents a method that returns a value.
Can take 0 to 16 input parameters, last type is the return type.

Func<int, int, int> add = (a, b) => a + b;
int sum = add(3, 4); // sum = 7

Why Use Action and Func?

Decouple logic from implementation.
Useful in LINQ, event handling, callbacks, dynamic method binding.
Helps implement design patterns with less boilerplate.

Real-World Example 1: Strategy Pattern Using Func
The Strategy Pattern allows you to swap algorithms dynamically.

Let’s build a tax calculator that can apply different tax strategies using Func.

Real-World Example 1: Strategy Pattern Using Func
The Strategy Pattern allows you to swap algorithms dynamically.

Let’s build a tax calculator that can apply different tax strategies using Func.

public class TaxCalculator
{
    private readonly Func<decimal, decimal> _taxStrategy;

    public TaxCalculator(Func<decimal, decimal> taxStrategy)
    {
        _taxStrategy = taxStrategy;
    }

    public decimal Calculate(decimal amount) => _taxStrategy(amount);
}

Usage

var standardTax = new TaxCalculator(amount => amount * 0.2m);
Console.WriteLine(standardTax.Calculate(100)); // Output: 20

var reducedTax = new TaxCalculator(amount => amount * 0.1m);
Console.WriteLine(reducedTax.Calculate(100)); // Output: 10`

Why It's Clean
No need for multiple strategy classes.
Easily inject behavior via Func.

Real-World Example 2: Command Pattern Using Action
The Command Pattern encapsulates a request as an object.

Let’s create a simple remote control that executes commands using Action.

public class RemoteControl
{
    private readonly Action _command;

    public RemoteControl(Action command)
    {
        _command = command;
    }

    public void PressButton() => _command();
}

Usage

var turnOnLight = new RemoteControl(() => Console.WriteLine("Light On"));
turnOnLight.PressButton(); // Output: Light On

var playMusic = new RemoteControl(() => Console.WriteLine("Music Playing"));
playMusic.PressButton(); // Output: Music Playing

Advantage

You can queue commands, undo, or log them — all using Action.

Combining Action and Func: Workflow Example
Let’s simulate a data processing pipeline:

Func<string> fetchData = () => "raw data";
Func<string, string> processData = data => data.ToUpper();
Action<string> saveData = result => Console.WriteLine($"Saved: {result}");

var raw = fetchData();
var processed = processData(raw);
saveData(processed); // Output: Saved: RAW DATA

*Final Thoughts : *

Understanding and leveraging Action and Func can simplify your code, especially when implementing common patterns. They enable dynamic, reusable behaviors that are perfect for modern C# development.

Next time you’re about to create multiple strategy or command classes, consider whether delegates can do the job with less overhead.

References

Official Microsoft Docs - Delegates

C# Action Delegate

C# Func Delegate

GitHub Repo: MakeUseOfActionAndFuncDelegate