Imagine that you are writing a method that transforms each element of a list into another element. You want this transformation to be arbitrary, user-defined. This would be implemented like this:
IEnumerable<TResult> Map<T, TResult>(IEnumerable<T> collection, Func<T, TResult> transform)
{
foreach(var item in collection)
yield return transform(item);
}
Thus, the user can pass as argument any function that receives one of the elements of the list (type T
) as argument and to transform it into another element (of type TResult
).
var list = new List<int> {1,2,3};
var doubled = Map(list, item => item * 2);
Moral of the story: Func<T, TResult>
(and any other delegate in general) serves to pass arbitrary functions. Serves to treat functions as objects/values (this is the pillar of the FP - Functional Programming paradigm).
This method I used as an example (Map
) is actually identical to the extension Enumerable.Select
. In fact, LINQ extensions rely heavily on passing delegates as arguments (Where
, Any
, All
, GroupBy
, OrderBy
, SelectMany
, SkipWhile
, etc.).
It is good to make clear also that
Func<>
as well as othersdelegate
s generics made available on . NET serve as a convenience to facilitate the life of the programmer. They wouldn’t need to exist, but they’re generic programming shortcuts so you don’t have to declare adelegate
new every time one is needed. That is, it is part of the utility of it to simplify the declaration of a type ofdelegate
s.– Trinidad