Func<T> and Action<T> are predefined delegate types used to pass methods (including lambdas) as parameters.
Summary:
-
Func<...>: method returns a value.
-
Action<...>: method does not return a value (void).
Both can have 0–16 input parameters:
-
Func<TResult> up to Func<T1,...,T16,TResult>
-
Action up to Action<T1,...,T16>
The last type parameter of Func is always the return type.
When to use each
Use Action<...> when:
- The method performs an operation and does not need to return anything.
- Example: logging, writing to console, updating a collection, sending a message.
Use Func<...> when:
- The method computes and returns a result from its inputs.
- Example: projections, calculations, predicates, transformations.
From the documentation:
-
Action<> is used when there is a need to perform an action using the arguments of the delegate. The method it encapsulates does not return a value.
-
Func<> is used when a transformation is needed; the method it encapsulates returns a specified value.
Basic examples
Func examples
A Func<string, int> that takes a string and returns its length:
Func<string, int> getLength = s => s.Length;
int len = getLength("hello"); // len == 5
A Func<string, int, bool> that checks if the string length equals a given number (from the docs):
Func<string, int, bool> predicate = (str, index) => str.Length == index;
string[] words = { "orange", "apple", "Article", "elephant", "star", "and" };
IEnumerable<string> aWords = words.Where(predicate).Select(str => str);
foreach (string word in aWords)
Console.WriteLine(word);
Here:
- Parameters:
string and int.
- Return type:
bool (TResult).
- Used as a parameter to
Where, which expects a Func<...>.
Another example using a named method instead of a lambda (from the docs):
Func<string, int, string[]> extractMethod = ExtractWords;
string title = "The Scarlet Letter";
foreach (string word in extractMethod(title, 5))
Console.WriteLine(word);
string[] ExtractWords(string phrase, int limit)
{
char[] delimiters = { ' ' };
return limit > 0 ? phrase.Split(delimiters, limit) : phrase.Split(delimiters);
}
Action examples
Action<string, string> that writes two strings to the console (from the docs):
Action<string, string> concat = WriteToConsole;
concat("The first line of a message.", "The second line of a message.");
void WriteToConsole(string string1, string string2)
{
Console.WriteLine("{0}\n{1}", string1, string2);
}
Same example using a lambda instead of a named method:
Action<string, string> concat = (s1, s2) =>
{
Console.WriteLine("{0}\n{1}", s1, s2);
};
concat("The first line of a message.", "The second line of a message.");
Action<string[], string[], int> that copies part of one array to another (from the docs):
Action<string[], string[], int> copyOperation = CopyStrings;
copyOperation(ordinals, copiedOrdinals, 3);
void CopyStrings(string[] source, string[] target, int startPos)
{
if (source.Length != target.Length)
throw new IndexOutOfRangeException("The source and target arrays must have the same number of elements.");
for (int ctr = startPos; ctr <= source.Length - 1; ctr++)
target[ctr] = source[ctr];
}
Passing Func and Action as parameters
A method that takes a Func<int, int> and applies it:
static int ApplyTwice(int value, Func<int, int> operation)
{
return operation(operation(value));
}
int result = ApplyTwice(3, x => x * 2); // (3 * 2) * 2 = 12
A method that takes an Action<string> and calls it:
static void NotifyUsers(IEnumerable<string> users, Action<string> notifier)
{
foreach (var user in users)
notifier(user);
}
NotifyUsers(new[] { "Alice", "Bob" }, name => Console.WriteLine($"Hello, {name}"));
Func vs Action in LINQ and TPL/PLINQ
Many .NET APIs accept Func/Action parameters, especially LINQ and TPL/PLINQ:
- LINQ operators like
Where, Select use Func delegates (they need to return a value, e.g., bool for filtering, a projection type for Select).
- TPL methods like
Parallel.ForEach often use Action when they just perform work on each element, and Func when they compute and return local state.
From the TPL/PLINQ documentation:
- The underlying type of a lambda expression is one of the generic
Func delegates, which makes it possible to pass a lambda expression as a parameter without explicitly assigning it to a delegate.
-
Action delegates encapsulate methods that do not return a value; type parameters represent only input parameters.
Rule of thumb
- If the delegate’s method returns something → use
Func<...> (last type is the return type).
- If the delegate’s method returns nothing (
void) → use Action<...>.
Func and Action avoid declaring custom delegate types and are the standard way to pass behavior (methods, lambdas) into APIs in modern .NET.
References:
- Delegates and lambdas
- Lambda Expressions in PLINQ and TPL
- Func<T1,T2,TResult> Delegate
- Action<T1,T2> Delegate
- Action<T1,T2,T3> Delegate
- Action<T1,T2,T3,T4> Delegate
- Action<T1,T2,T3,T4,T5> Delegate