C# LINQ Background Topics
Open Source Your Knowledge, Become a Contributor
Technology knowledge has to be shared and made accessible for free. Join the movement.
Extra credit - Action and Func
Feeling a bit overwhelmed? The content on this page is optional. It can make your life easier, but it requires a bit more knowledge to understand than the other content in this course. Feel free to skip to the next lesson if you want to.
Writing a delegate type for each delegate that you want to declare gets a bit repetitive. For example, suppose you were to write this SayHello
delegate:
private delegate void SayHello();
private SayHello helloFunction = () => Console.WriteLine("Hello!");
Looks good, right? But imagine if you later wanted to declare another delegate that can say goodbye? You could reuse the SayHello
type, but that doesn't make much sense, does it?
You could instead declare a new delegate type:
private delegate void SayGoodbye();
private SayGoodbye goodbyeFunction = () => Console.WriteLine("Goodbye!");
Notice that SayGoodbye
is, other than its name, exactly the same as SayHello
. Maybe it would be better to rename SayHello
to something more generic like SayAnything
...
private delegate void SayAnything();
private SayAnything helloFunction2 = () => Console.WriteLine("Hello!");
private SayAnything goodbyeFunction2 = () => Console.WriteLine("Goodbye!");
Then what do you do when you need to declare another delegate type that also takes no parameters and returns void
? Maybe that declaration should be called DoAnything
! But then you'd need to declare that type for every project that you work on...
See where this is headed?
Action type
There is a family of built-in delegate types that can be used to declare delegate variables without the need to define a custom type. The types that represent a delegate without a return value (void
return) are the Action
types in the System
namespace.
Here is an example using Action
to declare a delegate variable:
private Action supFunction = () => Console.WriteLine("Sup?!");
What if you want to pass some parameters to your delegate? That's covered as well. There's an Action<T>
that takes one parameter, or Action<T1, T2>
that takes two parameters, and so on all the way up to an Action
that takes 16 parameters.
Here's an example of a delegate that takes three parameters of different types:
private Action<string, int, bool> printThreeValues =
(s, i, b) => Console.WriteLine($"string: {s}, int: {i}, bool: {b}");
Func type
Action
is good for delegates that return void
, but what about delegates that return a value? That's where Func<TResult>
comes in. The Func
family of delegate types can return a value of any type you wish. For example:
private Func<int> twoPlusThree = () => 2 + 3;
What about passing parameters? Then you need Func<T, TResult>
for delegates that take one parameter, and Func<T1, T2, TResult>
for two parameters, etc. Just as with Action
, the framework has delegates that support all the way up to 16 parameters.
Here is an example of a delegate declaration that takes two string
parameters and returns an int
:
private Func<string, string, int> sumCharacters =
(s1, s2) => s1.Length + s2.Length;