Dan Donahue bio photo

Dan Donahue

Musician. Traveler. Programmer.

LinkedIn Github Stackoverflow

This post is part of a series:

Ok - this is the last part of my series about delegates and lambdas. Finally. But I wanted to mention a few helpers that .NET provides to make it easier to use delegates and lambdas in your code.

If you remember back to the first post of the series, I mentioned that to declare a delegate to be used as a parameter or anything else, you had to do this:

Well - .NET makes it slightly less tedious with the use of three framework classes, namely Action<T> (MSDN), Predicate<T> (MSDN) and Func<T> (MSDN). Let's look at an example of each.


Action<T>:

This class encapsulates a delegate that takes one parameter and does not return a value. Meaning, it is a contract that specifies one input parameter, the type of which is specified as a generic, and a void return type. This is useful for a variety of scenarios, but let me show you just one.

If you've noticed, when you create a List<T>, one of the methods on that list that is built-in for .NET is ForEach(Action<T> action). Using that, you can build for-each loops using delegates/lambdas. See below:

Or, you can just inline it all with a lambda expression like this:

By the way, Action<T> also comes in a few additional flavors, those being Action<T1, T2>, Action<T1, T2, T3> and so on. As you can probably guess, this just allows you to use them to define up to x input parameter types - the return value in all situations is still void.

Predicate<T>:

This is another .NET class representing another standard delegate situation. This one takes one parameter and returns a boolean value. This is actually PERFECT for our filter situation. Instead of having to create a delegate like the one at the top of this post, we can use this in it's place, since it does the same thing (takes in one argument, it's generic, but we can specify we want it to be of type TeamDTO and returns a boolean value). So let's see it in action:

Compare this piece of code to the one in the first post of the series and you see that I just replaced the delegate object I created with the Predicate - why re-invent what .NET already has?


Func<T>:

This one actually comes in a bunch of different flavors and is arguably the most powerful. And actually, if you look at the MSDN documentation, Func<T> is actually not even the correct form of the delegate - but this is how it's used in conversation. The actual name is Func<TResult>. And hopefully by now you're catching on and can guess what that means. Func<TResult> allows you to specify a delegate with no input parameters and a return value of TResult. Like Action<T>, Func<TResult> has variations that allow you to specify up to 4 input parameters, in addition to the return type. So you have Func<TResult>, Func<T, TResult>, Func<T1, T2, TResult>, Func<T1, T2, T3, TResult> and so on. Keep in mind if you use these that the last value will be the return value in any situation.

As a really simple example, imagine I wanted a function that returned all of the team names in a list. Here it is:

The first line defines a Func<T, TResult> that accepts a TeamDTO object and returns a string. Then the lambda shows that x is the input parameter and on the other side of the => is the return statement x.TeamName. The other part is just a for-loop which invokes the delegate.

So that's it for my series on delegates and lambda expressions. But it won't be the last time you hear about them. A lot of the examples in these posts were scholastic in nature, but they probably left you thinking that aside from being neat, where was the benefit? Where all of these helpers, and delegates in general, become really powerful is when you combine them with other features of .NET. So expect to see more of these in future posts. But hopefully these gave you a few ideas about where you could benefit from the use of delegates, or at least help your understanding about what exactly is going on when you type code into your IDE of choice.

Any questions/comments/feedback? Feel free to leave them below.