114

Can someone provide a good explanation (hopefully with examples) of these 3 most important delegates:

  • Predicate
  • Action
  • Func

What other delegates should a C# developer be aware of?

How often do you use them in production code?

8 답변


167

  • Predicate: essentially Func<T, bool>; asks the question "does the specified argument satisfy the condition represented by the delegate?" Used in things like List.FindAll.

  • Action: Perform an action given the arguments. Very general purpose. Not used much in LINQ as it implies side-effects, basically.

  • Func: Used extensively in LINQ, usually to transform the argument, e.g. by projecting a complex structure to one property.

Other important delegates:

  • EventHandler/EventHandler<T>: Used all over WinForms

  • Comparison<T>: Like IComparer<T> but in delegate form.


  • There's also System.Converter<TInput, TOutput>, though it's rarely used. - G-Wiz
  • The Converter is a nice delegate when a lot of Converting of Model into Business classes is needed, i.e. stum.de/2009/12/23/… - Michael Stum
  • EventHandler/EventHandler<T> appear all over outside of WinForms too. - Andy
  • @Andy: Somewhat... But less so in WPF for example. I agree that there's nothing WinForms-specific to it. - Jon Skeet

27

Action, Func and Predicate all belong to the delegate family.

Action : Action can take n input parameters but it returns void.

Func : Func can take n input parameters but it will always return the result of the provided type. Func<T1,T2,T3,TResult>, here T1,T2,T3 are input parameters and TResult is the output of it.

Predicate : Predicate is also a form of Func but it will always return bool. In simple words it is wrapper of Func<T,bool>.


9

In addition to Jon's answer, there is also

  • Converter<TInput, TOutput>: It's essentially Func<TInput, TOutput>, but with semantics. Used by List.ConvertAll and Array.ConvertAll, but personally haven't seen it anywhere else.


4

MethodInvoker is one which WinForms developers may use; it accepts no arguments and returns no results. It predates Action, and is still often used when invoking onto the UI thread since BeginInvoke() et al accept an untyped Delegate; although Action will do just as well.

myForm.BeginInvoke((MethodInvoker)delegate
{
  MessageBox.Show("Hello, world...");
});

I'd also be aware of ThreadStart and ParameterizedThreadStart; again most people will substitute an Action these days.


3

Predicate, Func and Action are inbuilt delegate instances of .NET. Each of these delegate instances could refer or point to user methods with specific signature.

Action delegate - Action delegate instances could point to methods that take arguments and returns void.

Func delegate - Func delegate instance could point to method(s) that take variable number of arguments and return some type.

Predicate - Predicates are similar to func delegate instances and they could point to methods that take variable number of arguments and return a bool type.


3

The others have already mentioned the correct uses of the specific delegates, but I would like to add something that will complete their answers. The names Func, Action, Predicate have mathematical background. In order to keep things simple I will give an informal definition of a mathematical function like this:

A function is a relationship between sets. We take a member of one set and use it as an input and the function maps this input to only one member of the other set. In other words, something gets input and produces output.

Again, informally, a mathematical predicate is a statement that may be true or false depending on it's variables. As others have mentioned a function that returns boolean.

And last, Action is a void function (Or the more mathematically correct name -void method or procedure)


2

Action and Func with lambda:

person p = new person();
Action<int, int> mydel = p.add;       /*(int a, int b) => { Console.WriteLine(a + b); };*/
Func<string, string> mydel1 = p.conc; /*(string s) => { return "hello" + s; };*/
mydel(2, 3);
string s1=  mydel1(" Akhil");
Console.WriteLine(s1);
Console.ReadLine();


0

Func is more LINQ friendly, can be passed in as a parameter. (point-free)

Predicate cannot, has to be wrapped again.

Predicate<int> IsPositivePred = i => i > 0;
Func<int,bool> IsPositiveFunc = i => i > 0;

new []{2,-4}.Where(i=>IsPositivePred(i)); //Wrap again

new []{2,-4}.Where(IsPositivePred);  //Compile Error
new []{2,-4}.Where(IsPositiveFunc);  //Func as Parameter

Linked


Related

Latest