HomeSearch

C# Func Object (Lambda That Returns a Value)

Use the syntax of the Func type with lambda expressions. A Func receives arguments and returns a value.
Func handles many arguments. The Func type is a parameterized type. We specify the number and kinds of parameters, and the type of the return value.
The Func type provides a way to store anonymous methods in a generalized and simple way. We can even use it in a data structure like an array to call a method by an index.
This program uses the lambda expression syntax with Func type instances to store anonymous methods. We see type parameters: these are specified in the angle brackets < and >.Lambdas

So: The first type parameters are the arguments to the methods, and the final type parameter is the return value.

Generic Class, MethodReturn

Func 1: The first Func receives an int and returns a string and it is declared as Func<int, string>.

Func 2: The second receives a bool and an int and returns a string. It is declared with Func<bool, int, string>.

Func 3: The third returns a value. This is based on the value of PI (just to make things interesting).

Int, uintStringsBool

Finally: This program calls the Invoke method on the Func type instances. Each of the Invoke calls uses different parameters.

C# program that uses Func generic type and lambdas using System; class Program { static void Main() { // // Create a Func that has 1 parameter and 1 return value. // ... Parameter is an integer, result value is a string. // Func<int, string> func1 = (x) => string.Format("string = {0}", x); // // Func instance with two parameters and one result. // ... Receives bool and int, returns string. // Func<bool, int, string> func2 = (b, x) => string.Format("string = {0} and {1}", b, x); // // Func instance that has no parameters and one result value. // Func<double> func3 = () => Math.PI / 2; // // Call the Invoke instance method on the anonymous functions. // Console.WriteLine(func1.Invoke(5)); Console.WriteLine(func2.Invoke(true, 10)); Console.WriteLine(func3.Invoke()); } } Output string = 5 string = True and 10 1.5707963267949
Call directly. We can call a Func directly, without specifying the Invoke() function. We just use the Func like a normal method and pass it the required arguments.
C# program that calls Func directly using System; class Program { static void Main() { Func<int, int> addOneHundred = a => a + 100; // We can call the Func directly without Invoke. Console.WriteLine(addOneHundred(10)); } } Output 110
Performance, Func. Should you change all your C# code to use Func invocations? This might decrease performance—using classic constructs like switch may be faster.SwitchBenchmark

Here: We create a 3-Func lookup table. It is created with 3 lambda expressions as its element values.

And: We test the Func lookup table against a switch statement. The results show a performance difference.

Results: We lose some performance with the Func invocations. Using a switch is faster (and probably simpler to understand).

C# program that tests Func performance using System; using System.Diagnostics; class Program { const int _max = 10000000; static void Main() { // A Func lookup table. var lookup = new Func<int, int>[] { a => a + 10, a => a + 20, a => a + 30 }; // Version 1: use Func table. var s1 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { if (Version1(lookup, i) == -1) { return; } } s1.Stop(); // Version 2: use switch. var s2 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { if (Version2(i) == -1) { return; } } s2.Stop(); Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); } static int Version1(Func<int, int>[] lookup, int i) { // Use lookup table. return lookup[i % 3](i); } static int Version2(int i) { // Use switch. switch (i % 3) { default: case 0: return i + 10; case 1: return i + 20; case 2: return i + 30; } } } Output 4.64 ns Func lookup table 3.58 ns Switch
Discussion. You cannot call the Invoke method with an invalid number of parameters. The Func type stores the required parameter types and uses those to generate the Invoke method signature.

And: You can use the Func type as a field, return value, local variable, or parameter in your C# programs.

Important: You must specify the full type name with the type parameters. In this way we can store delegates by their signatures.

Example: You can add the Func<int, string> as a field, and give it an identifier.

A summary. We looked at the Func parameterized type and used it with the lambda expression syntax. We stored anonymous functions inside Func pointers and then called Invoke.
© 2007-2019 Sam Allen. Every person is special and unique. Send bug reports to info@dotnetperls.com.
Home
Dot Net Perls