Func and Action delegates
The post contains information on the differences of Func/Action delegates and custom delegates. Hopefully it will give you enough code examples to make you a master in their usage.
The post contains information on the differences of Func/Action delegates and custom delegates. Hopefully it will give you enough code examples to make you a master in their usage.
When I started out writing this post I was going to do a "why you should consider using Func/Action IN STEAD of a delegate" post.
But when I got into the research I found out that there is definitely room for both.
But the theme of this blog post will be mainly Func and Action and on the what, how and where they should/shouldn't be used.
All the func/action examples in this post are in my git repository. In the future I might re-write all the examples using custom delegates (but don´t hold your breath)
So what are Func and Action?
Action delegate was introduced in Framework 2.0 and Func delegate was introduced in Framework 3.5, C# 3.0.
They are just methods you can pass around to somewhere, where they get executed.
Func and Action are predefined built-in generic delegates where you don't need to define a custom delegate (as with regular delegates).
Func type delegate has 17 different parameters from 1 to 17, 0-16 in parameters where the last parameter is always its return type. And if there is only one parameter it is also its return type.
The only difference between Func and Action delegates is that Func returns a value and Action return a void.
Predicate - special mention
From google predicate means
something which is affirmed or denied concerning an argument of a proposition.
In C# a predicate is a special purpose delegate. It does the same as Func<T,bool>, so it takes in a value and returns true/false.
But by using a Predicate
Examples sometimes use the wording "predicate" without the actual predicate keyword like this
Func<Product,bool> predicate = p => !p.Discontinued;
var productList = storeProducts.Where(predicate);
Historically Predicate came before Func/Action and therefore is the reason lots of .net API's use it.
Notice that here Where() takes in a "predicate" int the form Func<Product,bool> but does not take in a "real" Predicate
Delegate? You talk allot about delegates!
I'm not going deeper into delegates other than C# delegates are similar to pointers to functions in C/C++. They are basically reference type variables that hold the reference to a method. All delegates are derived from the System.Delegate class.
If you want to go deeper into technical details on delegates I recommend taking a look at the docs on delegates.
But lets take a look at them from the outside shall we.
Why would you use a delegate all together?
- Make your code more declarative.
- Separate type declarations and implementation (like with an interface).
- "Delegates and Interfaces are two distinct concepts in C# but they share a commonality. Both delegates and interfaces only include the declaration. Implementation is done by a different programming object" [1]
- Helps removing duplicate code. Can be used where only the logic in the middle of a method changes. This is a pattern called Hole in the middle
- Caching of expensive method calls were return values never change given the same input.
- In event-driven programming using multicasting and event handlers (buttonClick etc.)
- Write fewer lines of code for many common tasks.
When is a custom delegate is better than Func
There are places were you might be better off using a custom delegate than a generic Func or Action.
Lets take a look
- Use a delegate in your public API's for clarity. Even though that might be up for debate[2].
- If you want the delegate to have some special name. Giving more definition on what the delegate does.
- You need ref/out.
- You need optional parameters.
- You need param keyword.
- You are working with complicated function signatures. The code can get very unreadable fast [3].
- You need more than 16 parameters (probably not an issue)
- You are targeting an early version of C# where Func/Action do not exist.
When to use Func/Action instead of custom delegate
A man I respect allot told me this when I asked him for a good reason for using them instead of delegates.
"There's nothing particularly special about the Func and Action delegate types - but everyone knows them. Defining your own delegate types is reinventing the wheel.
That's useful if you need a new kind of wheel, but if it's the same kind of wheel everyone's already familiar with, why reinvent it?"
There are few others that might swing you to them.
- They save you the trouble of creating custom delegate type for each possible method signature.[3:1]
- Different custom delegate types are incompatible, even if their signatures exactly match. You can work around this but it's verbose.[3:2]
- Readability, e.g if a method accepts a Func<int,bool> you know the function takes in int and returns a bool. But if a method accepts a custom delegate I have to look up its signature.
The examples I will explore here below
I will now look at few usage examples for Func and Action that I thought were interesting.
All the examples can be found in my git repository.
- Simple Func example to start exploring
- Add/Multiply calculator example with Func
- Add/Multiply calculator example with Action
- How to benchmark all kinds of methods
- Caching CPU intensive methods calls to save money (if in e.g Azure)
- Write setup code once for many instances of same class
- Complex Switch statements (pre C# 7.0 code)
- Exception handling and logging moved out of class with "Safe Executor"
Please let me know if you know about any other interesting use cases I'm not covering here so I can add them to the list.
Delegate vs Func (in code)
But before we dive into the examples we should look at the difference between these two.
If you use a delegate you will need to define it. But with generic delegates (Func, Action, Predicate) they are defined already.
Using a custom delegate[4]
// Declare a delegate somewhere (could be in another project).
delegate string Del(string str);
// Declare a method with the same signature as the delegate.
static string Notify(string name)
{
return $"Notification received for: {name}";
}
...
// And then use the delegate like this somewhere
// Create an instance of the delegate.
Del del1 = new Del(Notify);
// C# 2.0 provides a simpler way to declare an instance of Del.
Del del2 = Notify;
// We can then call these delegates with either of the following syntaxes
string message1 = del1.Invoke("Called with Invoke");
// Some prefer using Invoke because it differentiates the delegate from a method
string message2 = del2("Called directly");
Or using anonymous method.
public static void Main()
{
Func<string, string> Notify = delegate (string name)
{
return $"Notification received for: {name}";
};
string result = Notify("Sturla");
System.Console.WriteLine($"{result}");
}
And then using a Func with Lambda Expression
public static void Main()
{
Func<string, string> Notify = s => "Hello "s + "!";
string result = Notify("Sturla");
Console.WriteLine($"{result}";
}
and then using a Func delegate
public static void Main()
{
Func<string, string> func = Notify;
string result = func("Sturla");
Console.WriteLine($"{result}";
}
public static string Notify(string name)
{
return $"Notification received for: {name}";
}
Another simple Func example
Here is the simplest of Func's. A Func that returns StateEntry but does not take in any other parameters, is passed to the ChangeState method where it is executed and the result from it used somewhere else.
List<StateEntry> dataBoundList = new List<StateEntry>();
public void ChangeState(Func<StateEntry> stateChangeFunction)
{
//the func gets executed
var entry = stateChangeFunction();
// use the result somewhere
dataBoundList.Add(entry);
}
ChangeState() can then accept all Func's that follow that signature. See examples of that here below.
Note that there are few different ways to write the Func when they are local to a method like here.
static void Main(string[] args)
{
// Using lambda
Func<StateEntry> wheatherChangeStateFunction = () =>
{
// state change code omitted
return new StateEntry() { StateChanged = true };
};
// Using anonymous method
Func<StateEntry> productionChangeStateFunction = delegate ()
{
// state change code omitted
return new StateEntry() { StateChanged = true };
};
// This is an local function that can be used instead of func.
// I think its a lot nicer and I would stick with this one
StateEntry customerChangeStateFunction()
{
// state change code omitted
return new StateEntry() { StateChanged = true };
}
//etc.
StateManager manager = new StateManager();
manager.ChangeState(wheatherChangeStateFunction);
manager.ChangeState(productionChangeStateFunction);
manager.ChangeState(customerChangeStateFunction);
}
Calculator (Func) example
Lets look at a small calculation example that can handle 2 numbers. It uses static methods that have a signature that matches the Func one that the Calculator has.
Lets say you have a Add method like this
public static int Add(int value1, int value2)
{
return value1 + value2;
}
and a multiplication method like so
public static int Multiply(int value1, int value2)
{
return value1 * value2;
}
And so on e.g subtraction, cubed etc.
The calculator it's self would then look like the following method that takes in two numbers and returns a result.
public int Calculator(int value1, int value2, Func<int, int, int> mathProbem)
{
return mathProbem(value1, value2);
}
To run the calculator and see all the different results do this
var mathRunner = new CalculatorLib.Calculator();
var additionResult = mathRunner.Calculate(o.Value1, o.Value2, Addition.Add);
var multiplyrResult = mathRunner.Calculate(o.Value1, o.Value2,Multiplication.Multiply);
var subtractResult = mathRunner.Calculate(o.Value1, o.Value2, Subtraction.Substract);
Calculator (Action) example
This example is basically the same as the Func calculator but does not return a value (using Action).
Note that the example is just logging out the result (yes I know that this example doesn't maybe make lot of sense but shows how Action works).
public void Calculate(int value1, int value2, Action<int, int> mathProbem)
{
mathProbem(value1, value2);
}
and here are the calculation methods (to be used with Calculate)
public static void Add(int value1, int value2)
{
var result = value1 + value2;
Log.Information("Result: {result}", result);
}
public static void Multiply(int value1, int value2)
{
var result = value1 * value2;
Log.Information("Result: {result}", result);
}
Benchmark example
Another great usage of the Action delegate is a benchmark method.
Lets say you have a method like this you want to measure performance on.
public void CalculateMillionPrimeNumbers()
{
for (int i = 0; i < 100; i++)
{
//No actual prime numbers where hurt in this example!
Thread.Sleep(10);
}
}
To measure its performance you can pass it to the Benchmark method where it gets measured.
public static void Benchmark(Action action)
{
var watch = new Stopwatch();
watch.Start();
action(); //Run the Action delegate
watch.Stop();
Log.Information("ElapsedMilliseconds: {elapsedMilliseconds}ms", watch.ElapsedMilliseconds);
}
Using this code is as simple as this
Performance.Benchmark(methods.CalculateMillionPrimeNumbers);
I added few more overrides (Func/Action/etc) to the Benchmark method in my GitHub repo for you to look at.
Note that if you need a real benchmarks (graphs, bells and whistles) you should try out BenchmarkDotNet (though not yet version 1) or something similar.
Memoize (caching of CPU expensive method calls)
If you don't know what Memoize is you should take a look at this example on how to use closures to memoize the results of a recursive function.
Lets say we need to do Fibonacci calculation (or some more intensive processing) we don't want to run those calculations over and over again for the same inputs.
What we want to do is to store (cache) the calclulated results so we can featch the again fast.
Here we setup the Memoize (caching) extension method and then run the Fibonacci method twice.
static void Main(string[] args)
{
Fibonacci = Fibonacci.Memoize();
// First usage of the expencive method
for (int i = 0; i < 50; i++)
Log.Information("{fib}", Fibonacci(i));
// If the Fibonacci(i) is run again every value
// is just fetched from the Dictionary that
// stores the results from the previous run
for (int i = 0; i < 50; i++)
Log.Information("{fib}", Fibonacci(i));
}
public static Func<int, int> Fibonacci = (n) =>
{
// We only go into here once. Second time this is cached.
return n > 1 ? Fibonacci(n - 1) + Fibonacci(n - 2) : n;
};
Notice that the second time we run it we don't do any calculation but get the results from the dictionary.
Here is another method that can be used with the Memoize() extension at the same time as the other one. Memoize() will store all the results from all the methods its used on.
public static Func<string, string> SuperComplexLowerCasing = (n) =>
{
Thread.Sleep(5000);
// I just didn't come up with anything more clever.
// Need to find my old Calculus books.
return n.ToLower();
};
Here are caching results for the second method.
SuperComplexLowerCasing = SuperComplexLowerCasing.Memoize();
// Some other super complex and time consuming lowercasing.
Log.Information("{lower}", SuperComplexLowerCasing("ChachedFirstTime"));//runs for 5 sec
Log.Information("{lower}", SuperComplexLowerCasing("ChachedFirstTime"));//will run fast because its cached
Log.Information("{lower}", SuperComplexLowerCasing("NotCached"));//runs for 5 sec
Log.Information("{lower}", SuperComplexLowerCasing("ChachedFirstTime"));//will run fast because its cached
And here is the caching extension method Memoize.
public static Func<TArgument, TResult> Memoize<TArgument, TResult>(this Func<TArgument, TResult> function)
{
var allMethodsDictionaries = new Dictionary<string, Dictionary<TArgument, TResult>>();
var name = function.Method.Name;
// If the this kind of function has not been cached (Memoized) before we need to create a dictionary and add it.
if (!allMethodsDictionaries.TryGetValue(name, out Dictionary<TArgument, TResult> functionDictionary))
{
functionDictionary = new Dictionary<TArgument, TResult>();
Log.Information("MethodName: {name}, ReturnType: {returnType}", name, function.Method.ReturnType);
allMethodsDictionaries.Add(name, functionDictionary);
}
return key =>
{
// If the value calculated was not in this function dictionary we need to calculate it and add it.
if (!functionDictionary.TryGetValue(key, out TResult value))
{
value = function(key);
functionDictionary.Add(key, value);
}
// If we have already got value cached from e.g Fibonacci(i) or it has been added to values
// there is no need to call the CPU expensive function because we already have the result in cache!
// So we return the previously calculated value.
return value;
};
}
Button setup example
Lets say
- you have 10 buttons (same type) on a page
- each button needs 5 lines of the same setup code
Imagine how the code will look like if you repeat those 5 lines 10 times!
Doing that for each and every button will make your code harder to read and maintain.
What you probably want to do is setting up the button only once.
// Clean setup of the code in one place
// Action delegate method with setup code we just want in one place
Action<Button, Action<Button>> setupButton = (btn, x) =>
{
btn.Height = 42;
btn.Width = 64;
btn.Color = "Red";
//...more setup code for a button
x(btn);
};
and then just do this
// new up 10 buttons without setting them up
var btn1 = new Button();
var btn2 = new Button();
var btn3 = new Button();
var btn4 = new Button();
var btn5 = new Button();
var btn6 = new Button();
var btn7 = new Button();
var btn8 = new Button();
var btn9 = new Button();
var btn10 = new Button();
// This makes the method shorter and the code more readable
// We just change code that is not part of the setup
setupButton(btn1, btn => btn.Text = "OK");
setupButton(btn2, btn => btn.Text = "Cancel");
setupButton(btn3, btn => btn.Text = "Save");
// etc.
Take a look at the code here
Switch example
Lets say you needed to switch on something that doesn't equal to something (it doesn't give you a boolean valu).
For example you needed to switch on something that is less than (<).
// Actions don't return so we log out if a number is found
var actionSwitch = new Dictionary<Func<int, bool>, Action>
{
{ x => x < 0 , () => Log.Information("{val}","n/a")}, //Note that you can't do "x < 0" in a ordinary Switch statement
{ x => x == 0, () => Log.Information("{val}","0")},
{ x => x == 1, () => Log.Information("{val}","1")},
{ x => x == 2, () => Log.Information("{val}","2")},
{ x => x == 3, () => Log.Information("{val}","3")},
{ x => x == 4, () => Log.Information("{val}","4")},
{ x => x == 5, () => Log.Information("{val}","5")},
};
var actionSwitchResult = actionSwitch.FirstOrDefault(sw => sw.Key(Convert.ToInt32(numberToFind)));
if (actionSwitchResult.Key != null)
{
actionSwitch.FirstOrDefault(sw => sw.Key(Convert.ToInt32(numberToFind))).Value();
}
and a similar Func example
var funcSwitch = new Dictionary<Func<int, bool>, Func<string>>
{
{ x => x < 0 , () => "n/a"}, //Note that you can't do "x < 0" in a ordinary Switch statement
{ x => x == 0, () => "0"},
{ x => x == 1, () => "1" },
{ x => x == 2, () => "2"},
{ x => x == 3, () => "3"},
{ x => x == 4, () => "4"},
{ x => x == 5, () => "5"},
};
string returnValue = string.Empty;
var funcSwitchReulst = funcSwitch.FirstOrDefault(sw => sw.Key(Convert.ToInt32(numberToFind)));
if (funcSwitchReulst.Key != null)
{
// Please let me know how I can null check this line with Value()
// called so I don't have to check if the .Key is null.
// I am tired and don´t have time/stamina to figure this out now :-)
returnValue = funcSwitch.FirstOrDefault(sw => sw.Key(Convert.ToInt32(numberToFind))).Value();
}
if (returnValue?.Length == 0)
{
Log.Information($"The return value: Did not find '{numberToFind}'");
}
else
{
Log.Information("The return value: {value}", returnValue);
}
But after C# 7.0 this is much easier to do (see example in my GitHub repo).
Safe executor helper
Here I'm showing you how to move all your common exception handling and error logging out of your class to one place.
Lets say you have a web API Controller actions where you don't like to repeat the same exception handling and logging for each and every API call you can do something like this.
public async Task<SomeResponse> SomeWebControllerApi(SomeRequest request)
{
// this func can probably be made easier on the eye
Func<SomeRequest, Task<SomeResponse>> function = async (SomeRequest r) =>
{
return await ErrorHelper.ReadResponse<SomeResponse>(await Task.Run(() => { return FakingConnectionOverTheInternet(); }));
};
// No need to have try/catch or logging. Its all done in the SafeExecutor method
return await ErrorHelper.SafeExecutor(function, request);
}
Its an interesting code so I recommend that you read through it here to see if you can use any of it in your project.
Another way to move try catch logic from your method
Here is one way you can keep the try catch out of your methods and just in one place. Use a expression body /fat arrow function
private delegate Task<SomeResponse> ReturnSomeResponseFunction();
private async Task<SomeResponse> TryCatch(ReturnSomeResponseFunction func)
{
try
{
return await func;
}
catch(Exception ex)
{
// handle your exception
}
catch(NotImplementedException ex)
{
......
}
catch(SomeOtherException ex)
{
......
}
}
//Now you can call your methods like this
public Task<SomeResponse> SomeWebControllerApi(SomeRequest request) =>
TryCatch(async () =>
{
// your logic
return await DoStuff();
});
Last words
Man this was a long blog :-) I really hope you learned something because I sure know I did researching it.
I will probably add to this article as time goes by because I recently bought the book Functional Programming in C#: How to write better C# code which I highly recommend.