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:
- What Action and Func are
- How to use them effectively
- 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