C# Func
last modified April 22, 2025
This tutorial explores the Func
delegate in C#, a powerful tool
for functional programming, enabling concise and expressive code.
Unlike languages with first-class functions, C# relies on delegates like
Func
to emulate functional programming. Combined with lambda
expressions, Func
reduces verbosity and enhances code flexibility,
as seen in LINQ and other scenarios.
C# Func
Func is a built-in generic delegate type, alongside
Predicate
and Action
. It supports methods, anonymous
methods, or lambda expressions, offering versatility in functional programming.
Func
supports 0 to 16 input parameters and requires a return type.
With 16 overloads, it accommodates various method signatures.
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
This delegate represents a method with two input parameters and a return value
of type TResult
.
C# Func simple example
This example demonstrates basic usage of the Func
delegate.
string GetMessage() { return "Hello there!"; } Func<string> sayHello = GetMessage; Console.WriteLine(sayHello());
The example uses a Func
delegate with no parameters, returning a
string from a method.
string GetMessage() { return "Hello there!"; }
The GetMessage
method is referenced by the Func
delegate.
Func<string> sayHello = GetMessage;
The delegate is assigned to reference GetMessage
, simplifying
method invocation.
Console.WriteLine(sayHello());
The delegate invokes the method, printing the result.
$ dotnet run Hello there!
C# Func examples
This example uses Func
to perform addition.
int Sum(int x, int y) { return x + y; } Func<int, int, int> add = Sum; int res = add(150, 10); Console.WriteLine(res);
The Sum
method is referenced via a Func
delegate to
add two integers.
Func<int, int, int> add = Sum;
The delegate accepts two integers and returns their sum.
$ dotnet run 160
This example extends Func
to three parameters.
int Sum(int x, int y, int z) { return x + y + z; } Func<int, int, int, int> add = Sum; int res = add(150, 20, 30); Console.WriteLine(res);
The delegate references a method summing three integers.
$ dotnet run 200
This example shows a custom delegate without Func
.
int Sum(int x, int y) { return x + y; } Add AddTwo = Sum; int res = AddTwo(150, 10); Console.WriteLine(res); delegate int Add(int x, int y);
A custom delegate is used instead of Func
, illustrating the
additional boilerplate required.
C# Func with lambda expression
Lambda expressions streamline Func
creation using the
=>
operator, enhancing code conciseness.
Func<int, int, int> randInt = (n1, n2) => new Random().Next(n1, n2); Console.WriteLine(randInt(1, 100));
The example generates a random integer within a range using a lambda-based
Func
.
C# Func Linq Where
Many LINQ methods, like Where
, accept Func
delegates
to filter sequences based on predicates.
Func<string, bool> HasThree = str => str.Length == 3; string[] words = [ "sky", "forest", "wood", "cloud", "falcon", "owl" , "ocean", "water", "bow", "tiny", "arc" ]; IEnumerable<string> threeLetterWords = words.Where(HasThree); foreach (var word in threeLetterWords) { Console.WriteLine(word); }
The example filters words with exactly three letters using a
Func
-based predicate.
Func<string, bool> HasThree = str => str.Length == 3;
The lambda expression checks if a string's length is three, returning a boolean.
IEnumerablethreeLetterWords = words.Where(HasThree);
The Where
method applies the predicate to filter the array.
$ dotnet run sky owl bow arc
C# list of Func delegates
Func
delegates can be stored in collections for dynamic function
application.
int[] vals = [1, 2, 3, 4, 5]; Func<int, int> square = x => x * x; Func<int, int> cube = x => x * x * x; Func<int, int> inc = x => x + 1; List<Func<int, int>> fns = [ inc, square, cube ]; foreach (var fn in fns) { var res = vals.Select(fn); Console.WriteLine(string.Join(", ", res)); }
The example applies multiple Func
delegates from a list to an
array, demonstrating dynamic transformations.
$ dotnet run 2, 3, 4, 5, 6 1, 4, 9, 16, 25 1, 8, 27, 64, 125
C# Func filter array
This example filters an array of user objects using a Func
delegate.
User[] users = [ new (1, "John", "London", "2001-04-01"), new (2, "Lenny", "New York", "1997-12-11"), new (3, "Andrew", "Boston", "1987-02-22"), new (4, "Peter", "Prague", "1936-03-24"), new (5, "Anna", "Bratislava", "1973-11-18"), new (6, "Albert", "Bratislava", "1940-12-11"), new (7, "Adam", "Trnava", "1983-12-01"), new (8, "Robert", "Bratislava", "1935-05-15"), new (9, "Robert", "Prague", "1998-03-14"), ]; var city = "Bratislava"; Func<User, bool> livesIn = e => e.City == city; var res = users.Where(livesIn); foreach (var e in res) { Console.WriteLine(e); } record User(int Id, string Name, string City, string DateOfBirth);
The program filters users living in Bratislava using a Func
predicate.
var city = "Bratislava"; FunclivesIn = e => e.City == city;
The predicate checks if a user's city matches "Bratislava".
var res = users.Where(livesIn);
The Where
method applies the predicate to filter the array.
$ dotnet run User { Id = 5, Name = Anna, City = Bratislava, DateOfBirth = 1973-11-18 } User { Id = 6, Name = Albert, City = Bratislava, DateOfBirth = 1940-12-11 } User { Id = 8, Name = Robert, City = Bratislava, DateOfBirth = 1935-05-15 }
C# Func filter by age
This example filters users by age using a Func
delegate.
List<User> users = [ new (1, "John", "London", "2001-04-01"), new (2, "Lenny", "New York", "1997-12-11"), new (3, "Andrew", "Boston", "1987-02-22"), new (4, "Peter", "Prague", "1936-03-24"), new (5, "Anna", "Bratislava", "1973-11-18"), new (6, "Albert", "Bratislava", "1940-12-11"), new (7, "Adam", "Trnava", "1983-12-01"), new (8, "Robert", "Bratislava", "1935-05-15"), new (9, "Robert", "Prague", "1998-03-14"), ]; var age = 60; Func<User, bool> olderThan = e => GetAge(e) > age; var res = users.Where(olderThan); foreach (var e in res) { Console.WriteLine(e); } int GetAge(User user) { var dob = DateTime.Parse(user.DateOfBirth); return (int)Math.Floor((DateTime.Now - dob).TotalDays / 365.25D); } record User(int Id, string Name, string City, string DateOfBirth);
The program filters users older than 60 using a Func
delegate.
Func<User, bool> olderThan = e => GetAge(e) > age;
The predicate uses GetAge
to compute and compare user ages.
var res = users.Where(olderThan);
The Where
method filters users based on the predicate.
int GetAge(User user) { var dob = DateTime.Parse(user.DateOfBirth); return (int) Math.Floor((DateTime.Now - dob).TotalDays / 365.25D); }
The GetAge
method calculates a user's age from their birth date.
$ dotnet run User { Id = 4, Name = Peter, City = Prague, DateOfBirth = 1936-03-24 } User { Id = 6, Name = Albert, City = Bratislava, DateOfBirth = 1940-12-11 } User { Id = 8, Name = Robert, City = Bratislava, DateOfBirth = 1935-05-15 }
C# Predicate
Predicate
is a specialized Func
that returns a boolean,
used for single-argument predicates.
All Predicate
functionality can be achieved with
Func
, but Predicate
offers a clearer intent.
User[] users = [ new (1, "John", "London", "2001-04-01"), new (2, "Lenny", "New York", "1997-12-11"), new (3, "Andrew", "Boston", "1987-02-22"), new (4, "Peter", "Prague", "1936-03-24"), new (5, "Anna", "Bratislava", "1973-11-18"), new (6, "Albert", "Bratislava", "1940-12-11"), new (7, "Adam", "Trnava", "1983-12-01"), new (8, "Robert", "Bratislava", "1935-05-15"), new (9, "Robert", "Prague", "1998-03-14"), ]; var age = 60; Predicate<User> olderThan = e => GetAge(e) > age; var res = Array.FindAll(users, olderThan); foreach (var e in res) { Console.WriteLine(e); } int GetAge(User user) { var dob = DateTime.Parse(user.DateOfBirth); return (int) Math.Floor((DateTime.Now - dob).TotalDays / 365.25D); } record User(int Id, string Name, string City, string DateOfBirth);
The example uses a Predicate
to find users older than 60.
PredicateolderThan = e => GetAge(e) > age;
The Predicate
implicitly returns a boolean, simplifying the
signature.
var res = Array.FindAll(users, olderThan);
The Array.FindAll
method filters elements matching the predicate.
int GetAge(User user) { var dob = DateTime.Parse(user.DateOfBirth); return (int) Math.Floor((DateTime.Now - dob).TotalDays / 365.25D); }
The GetAge
method computes the user's age.
$ dotnet run User { Id = 4, Name = Peter, City = Prague, DateOfBirth = 1936-03-24 } User { Id = 6, Name = Albert, City = Bratislava, DateOfBirth = 1940-12-11 } User { Id = 8, Name = Robert, City = Bratislava, DateOfBirth = 1935-05-15 }
C# pass Func as parameter
This example passes a Func
delegate as a method parameter.
List<Person> data = [ new ("John Doe", "gardener"), new ("Robert Brown", "programmer"), new ("Lucia Smith", "teacher"), new ("Thomas Neuwirth", "teacher") ]; ShowOutput(data, r => r.Occupation == "teacher"); void ShowOutput(List<Person> list, Func<Person, bool> condition) { var data = list.Where(condition); foreach (var person in data) { Console.WriteLine("{0}, {1}", person.Name, person.Occupation); } } record Person(string Name, string Occupation);
The ShowOutput
method filters and displays persons based on a
Func
predicate.
void ShowOutput(List<Person> list, Func<Person, bool> condition)
The method accepts a Func
delegate to filter the list dynamically.
$ dotnet run Lucia Smith, teacher Thomas Neuwirth, teacher
C# Func compose
This example demonstrates composing Func
delegates by chaining
transformations.
int[] vals = [1, 2, 3, 4, 5]; Func<int, int> inc = e => e + 1; Func<int, int> cube = e => e * e * e; var res = vals.Select(inc).Select(cube); foreach (var e in res) { Console.WriteLine(e); }
The example chains Func
delegates to increment and cube array
elements.
Func<int, int> inc = e => e + 1; Func<int, int> cube = e => e * e * e;
Two Func
delegates define increment and cubing operations.
var res = vals.Select(inc).Select(cube);
The Select
method chains the transformations, applying them
sequentially.
$ dotnet run 8 27 64 125 216
C# Func with async method
This example uses Func
with an asynchronous method to simulate a
delayed computation.
Func<Task<int>> getRandomAsync = async () => { await Task.Delay(1000); // Simulate async work return new Random().Next(1, 100); }; int result = await getRandomAsync(); Console.WriteLine($"Random number: {result}");
The program defines a Func
that returns a Task
,
generating a random number after a delay.
C# Func with LINQ aggregation
This example uses Func
with LINQ to compute an aggregate value.
int[] numbers = [10, 20, 30, 40, 50]; Func<int, int> doubleValue = x => x * 2; var sum = numbers.Select(doubleValue).Sum(); Console.WriteLine($"Sum of doubled values: {sum}");
The program doubles each number using a Func
and computes the sum
with LINQ's Sum
method.
C# Func with Dynamic Parameter
This example showcases how to dynamically construct a Func
delegate
in C# based on a runtime condition. The flexibility provided by
Func
delegates allows developers to create reusable, encapsulated
logic that can be passed as parameters or assigned dynamically depending on the
application's requirements.
string[] words = { "apple", "banana", "cherry", "date" }; string filterType = "long"; // Can be "short" or "long" Func<string, bool> filter = filterType == "long" ? s => s.Length > 5 : s => s.Length <= 5; var filteredWords = words.Where(filter); foreach (var word in filteredWords) { Console.WriteLine(word); }
In this program, the Func<T, TResult>
delegate is used to
create a predicate function that filters an array of words based on their
length. The Func<T, TResult>
delegate represents a method
that takes a single input of type T
and returns a result of type
TResult
. Here, the input type is string
, and the
result type is bool
, which makes the Func
suitable for
defining a condition that evaluates to either true or false.
The filterType
variable determines the behavior of the filtering
function. If the value of filterType
is set to "long," the program
assigns a lambda expression s => s.Length > 5
to the
filter
variable. This lambda checks whether the length of each word
is greater than 5. Conversely, if the value of filterType
is
"short," a different lambda expression, s => s.Length <= 5
,
is assigned, which checks whether the word length is 5 or less.
The dynamically assigned Func
is then passed as a predicate to the
Where
method of the IEnumerable<T>
interface.
The Where
method filters the sequence of words using the condition
defined in the filter
. This results in a collection containing only
the words that satisfy the specified condition. Finally, the filtered words are
iterated over and printed to the console, allowing users to see the dynamically
filtered output.
C# Func with Error Handling
This example demonstrates how to incorporate error handling within a
Func
delegate in C#. By embedding try-catch blocks directly into a
lambda expression, the program ensures robust and reliable processing, even when
faced with invalid or unexpected inputs. This approach is particularly useful
when handling dynamic data, such as user input or external data sources, where
errors are more likely to occur.
Func<string, int> parseNumber = s => { try { return int.Parse(s); } catch (FormatException) { Console.WriteLine($"Error: '{s}' is not a valid number"); return 0; } }; string[] inputs = { "123", "abc", "456" }; var results = inputs.Select(parseNumber); foreach (var result in results) { Console.WriteLine($"Result: {result}"); }
The Func<string, int>
delegate in this program is used to
define a lambda expression for parsing strings into integers. It encapsulates
logic for converting a string representation of a number into its integer
equivalent while handling potential exceptions gracefully.
Error handling is integrated using a try
-catch
block
within the lambda expression. If the input string cannot be parsed due to an
invalid format (e.g., non-numeric characters), a FormatException
is
thrown. The catch
block captures this exception and provides
meaningful feedback to the user by printing an error message that specifies the
invalid input. Instead of crashing the program, the lambda expression returns a
default value of 0
, allowing the application to continue processing
other inputs seamlessly.
The Select
method of the IEnumerable<T>
interface applies the Func<string, int>
delegate to each
element of the inputs
array. This results in a collection of
integers where valid numbers are converted, and invalid inputs are replaced with
the default value of 0
. The filtered results are then iterated over
using a foreach
loop, and each parsed value is displayed on the
console, ensuring visibility into both successful and failed parsing attempts.
This implementation is particularly useful in scenarios where data integrity cannot be guaranteed, such as user-entered values in a form or data retrieved from external sources like files, APIs, or databases.
Source
This article explored advanced uses of the C# Func
delegate,
including LINQ, async methods, and error handling.
Author
List all C# tutorials.