Imagine you are writing a method that transforms each element of a list into another element. You want this transformation to be arbitrary, and defined by the user. 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 (of type T
) as argument and that turns 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. It 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 Enumerable.Select
". In fact, LINQ extensions depend heavily on passing delegates as arguments ( Where
, Any
, All
, GroupBy
, OrderBy
, SelectMany
, SkipWhile
, etc).