Creating delegates manually vs using Action/Func delegates
Solution 1
The advantage is clarity. By giving the type an explicit name it is more clear to the reader what it does.
It will also help you when you are writing the code. An error like this:
cannot convert from Func<string, int, double> to Func<string, int, int, double>
is less helpful than one which says:
cannot convert from CreateListAction to UpdateListAction
It also means that if you have two different delegates, both of which take the same types of parameters but conceptually do two entirely different things, the compiler can ensure that you can't accidentally use one where you meant the other.
Solution 2
The advent of Action
and Func
family of delegates has rendered custom delegates less used, but the latter still finds uses. Advantages of custom delegates include:
As others have pointed, conveys intent clearly unlike generic
Action
andFunc
(Patrik has a very good point about meaningful parameter names).-
You can specify
ref
/out
parameters unlike the other two generic delegates. For eg, you can havepublic delegate double ChangeListAction(out string p1, ref int p2);
but not
Func<out string, ref int, double> ChangeListAction;
Also, with custom delegates you need to write
ChangeListAction
(I mean the definition) only once somewhere in your code base, whereas if you don't define one you will have to litter everywhereFunc<string, int, double>
all over. Changing the signature will be a hassle in the latter case - a bad case of not being dry.-
Can have optional parameters.
public delegate double ChangeListAction(string p1 = "haha", int p2);
but not
Func<string, int, double> ChangeListAction = (p1 = "haha", p2) => (double)p2;
-
You can have
params
keyword for parameters of a method, not so withAction/Func
.public delegate double ChangeListAction(int p1, params string[] p2);
but not
Func<int, params string[], double> ChangeListAction;
Well, if you're truly out of luck and need parameters more than 16 (for the moment) :)
As to merits of Action
and Func
:
It's quick and dirty, and I use it all over. It makes code short if the use-case is trivial (custom delegates have gone out of fashion with me).
More importantly, its type compatible across domains.
Action
andFunc
are framework defined, and they operates seamlessly as long as the parameter types match. You can't haveChangeSomeAction
forChangeListAction
.Linq
finds great use of this aspect.
Solution 3
Declaring a delegate explicitly can help with some type checks. The compiler can make sure that the delegate assigned to the variable is intended to be used as ChangeListAction and not some random action that happens to be compatible with the signature.
However the real value of declaring your own delegate is that it gives it semantic meaning. A person reading the code will know what the delegate is doing by its name. Imagine if you had a class with three int fields but instead you declared an array of three int elements. The array can do the same thing but the names of the fields bring semantic information that is useful to the developers.
You should use Func, Predicate and Action delegates when you are designing a general purpose library like LINQ. In this case the delegates do not have a predefined semantics other than the fact that they will execute and action or be used as a predicate.
On a side note there is a similar tradeoff issue with Tuple vs anonymous type vs declaring your own class. You could just stick everything in a Tuple but then the properties are just Item1, Item2 which tells nothing about the use of the type.
Solution 4
As some answers mention the win is clarity, you name the type and so it will be easier to understand for a user of your api. I'd say - in most cases - declare delegate types for your public apis but it's quite alright to use Func<?,?>
internally.
One huge benefit of declaring the delegate type that is not mentioned in the other answers is that aside from giving the type a name you actually get to name the parameters also, this will massively increase the usability.
Solution 5
I have found a special use case where you can only use delegate:
public delegate bool WndEnumProc(IntPtr hwnd, IntPtr lParam);
[DllImport("User32.dll")]
public static extern bool EnumWindows(WndEnumProc lpEnumFunc, IntPtr lParam);
Using Func/Action just does not work: 'Namespace.Class.WndEnumProc' is a 'field' but is used like a 'type'
:
public Func<IntPtr, IntPtr, bool> WndEnumProc;
[DllImport("User32.dll")]
public static extern bool EnumWindows(WndEnumProc lpEnumFunc, IntPtr lParam);
Following code does compile, but throws exception when running because System.Runtime.InteropServices.DllImportAttribute
does not support marshaling of generic types:
[DllImport("User32.dll")]
public static extern bool EnumWindows(Func<IntPtr, IntPtr, bool> lpEnumFunc, IntPtr lParam);
I present this example to show to every one that: sometimes delegate is your only choice. And this is a reasonable answer to your question why not use Action<T>/Func<T> ?
Comments
-
Elisabeth almost 2 years
Today I was thinking about declaring this:
private delegate double ChangeListAction(string param1, int number);
but why not use this:
private Func<string, int, double> ChangeListAction;
or if
ChangeListAction
would have no return value I could use:private Action<string,int> ChangeListAction;
so where is the advantage in declaring a delegate with the
delegate
keyword?Is it because of .NET 1.1, and with .NET 2.0 came
Action<T>
and with .NET 3.5 cameFunc<T>
? -
Elisabeth over 13 yearsThe Func<T1,T2,U> has a name like Func<T1,T2,T3,U> so should the compiler not say: Can not convert from Func1Name to Func2Name then it would NOT be less helpful.
-
Marwie over 9 yearsHere's another one where you cannot use Func - you cannot use Func if it has to return itself as mentionned here: stackoverflow.com/questions/27989296/…
-
nawfal over 9 yearsthanks @Marwie. Helpful. Will add to my answer at some point.
-
Jalal almost 8 yearsIn example #5
params
must be last parameter. -
nawfal almost 8 years@Jalal you're right. Silly mistake. Anyone can edit answers anytime :)
-
Kind Contributor almost 6 yearsYou alluded to this with "LINQ". I believe Action/Func, are the foundation of anonymous (closure) methods.
-
nawfal almost 6 years@Todd I dont get you tbh. My answer isnt about LINQ.
-
Kind Contributor almost 6 yearsSorry, I tried too hard to keep my comment short. You are alluding to a very important reason why Action/Func are there at all. The reason "WHY" contributes a lot toward understanding the differences between Action/Func and delegate. You said
Linq finds great use of this aspect.
. Highlighting: Action and Func operate seamlessly across domains. I am saying there's more to this: Action/Func were fundamentaly created for anonymous (closure) methods (and Expressions) which enable LINQ and Fluent-like coding interfaces in C#. -
nawfal almost 6 years@Todd Having built-in delegates (like Func) were a necessity for LINQ to work (both for to-objects as well as to-entities) and generally useful to have built-in types, whereas closures existed in C# even before .NET 3.5. Action/Func are not needed for writing an anonymous methods in C#, nor it is the only delegate type that be compiled to using expression trees. Having built-in types just made everything easier in .NET. And no, I dont allude that Action/Func are there for LINQ reason, I simply dont know.
-
Kind Contributor almost 6 yearsAgain, I am just trying to help readers, but we seem to be decending into a fruitless argument. I should have been specific and described them as lambda expressions" not anonymous functions:
delegate(string s) { Console.WriteLine(s); }
was possible in C# 2.0. When I spoke of anonymous (closure) methods, I was referring to the C# language feature, not the IL implementation nor support for it. I'm sure it was possible to compile C# anonymous functions with delegates before. Lambda functions and LINQ were both introduced in C# version 3. -
nawfal almost 6 years@Todd Fruitless maybe but I too want to make it clear that Action/Func aren't the foundations of lambda expressions. Latter could be used with any delegate type. Action/Func just made anonymous methods more accessible/easier to use.
-
Kind Contributor almost 6 yearsLINQ was released along with C# version 3. The connection is objectively there. One does not use the
delegate(type param) { body }
syntax. The C# language treats them as Action<>/Func<>. This is a very important point. Kindly provide an example where I may be mistaken.Action/Func just made anonymous methods more accessible/easier to use
- I disagree, the Async/Func syntax is embedded in the C# language, before C# version 3, this syntax didn't exist. While it's possible a delegate anon syntax could have been used, it wasn't. I'm describing what is reality, not what could have been. -
nawfal almost 6 years@Todd One does not use the delegate(type param) { body } - There is no objective connection as
new List<string>().Any(delegate (string param) { return true; })
is equally valid syntax. -
nawfal almost 6 yearsAsync/Func syntax is embedded in the C# language. I think you are mistaking the connection between a delegate type like
Func
like and syntax for expressing an anonymous function. No,Func
syntax isn't embedded in the language. There is no syntax forFunc
in C#.Func
is nothing special, it is just another type declared in BCL, for sort of enabling structural typing (for functions). You could writeFunc<int, string> d = delegate(int param) { return ""; };
as well asMyCustomDelegate = param => "";
Or you are using wrong terminology to convey. -
nawfal almost 6 yearsI stick to my initial point, Action/Func are neither the foundations of lambda expressions nor anonymous methods. The word foundation has a strong connotation. I would say Action/Func were good helpers to have, just made the whole closure thing damn easier.
-
Kind Contributor almost 6 years1) When do you see
delegate (string param) { return true; })
in the usual LINQ documentation? They use(param) => { return true; }
which is a Func<int, bool>, or(param) => true
which is also Func<int, bool>. 2) No it is C#, founded on BCL and IL:(param) => {return true;}
is C# syntax which compiles to Func<int,bool> which inherits from delegate. 3) "neither foundations of lambda" - I was referring to LINQ not the broader lambda expression capability. They both come out in the same language, and LINQ examples use the() => {}
structure not the delgate one. Therefore: correlated. -
Kind Contributor almost 6 yearsLet us continue this discussion in chat.