I know how to use Action
and Func
in .NET, but every single time I start to, the exact same solution can be achieved with a regular old Method that I call instead.
This excludes when an Action
or Func
is used as an argument for something I don't control, like LINQ's .Where
.
So basically my question is...why do these exist? What do they give me extra and new that a simple Method doesn't?
Func is a delegate that points to a method that accepts one or more arguments and returns a value. Action is a delegate that points to a method which in turn accepts one or more arguments but returns no value. In other words, you should use Action when your delegate points to a method that returns void.
A Func in C# is a way to define a method in-line that has a return value. There is a similar concept of an Action that doesn't have a return value, but we'll get to that in a sec. The return value's type is always the last generic parameter on the Func 's definition.
The main difference between them is that a function can be used inside expressions directly on the screen, while an action can't. But you can still use an function as a regular action in your flows, because the function is still an action.
Func<T> and its equivalent delegate types are used for methods that return values (functions). T represents the return value. Action and its equivalent delegate types are used for methods that have no return value (procedures). Predicate is just an alternative form of Func<bool> that returns a boolean.
I think other answers here talk about what an Action
/Func
is and its use. I will try to answer how to choose between Action
/Func
and method. The differences first:
1) From a raw performance point of view, delegates are slower compared to direct method calls, but it's so insignificant that worrying about it is a bad practice.
2) Methods can have overloads (same function names with different signatures) but not Action
/Func
delegates since they are declared as variables and by C# rules you cant have two variables with the same name in a given scope.
bool IsIt() { return 1 > 2; } bool IsIt(int i) { return i > 2; } //legal Func<bool> IsIt = () => 1 > 2; Func<int, bool> IsIt = i => i > 2; //illegal, duplicate variable naming
3) Consequently, Action
/Func
are reassignable and can point to any function, while methods once compiled remain to be the same forever. It is semantically wrong to use Func/Action
if the method it points to never changes during run time.
bool IsIt() { return 1 > 2; } //always returns false Func<bool> IsIt = () => 1 > 2; IsIt = () => 2 > 1; //output of IsIt depends on the function it points to.
4) You can specify ref
/out
parameters for normal methods. For eg, you can have
bool IsIt(out string p1, ref int p2) { return 1 > 2; } //legal Func<out string, ref int, bool> IsIt; //illegal
5) You cannot introduce new generic type parameter for Action
/Func
(they are generic already btw, but the type arguments can only be a known type or types specified in the parent method or class), unlike methods.
bool IsIt<A, R>() { return 1 > 2; } //legal Func<bool> IsIt<A, R> = () => 1 > 2; //illegal
6) Methods can have optional parameters, not Action
/Func
.
bool IsIt(string p1 = "xyz") { return 1 > 2; } //legal Func<string, bool> IsIt = (p1 = "xyz") => 1 > 2; //illegal
7) You can have params
keyword for parameters of a method, not so with Action
/Func
.
bool IsIt(params string[] p1) { return 1 > 2; } //legal Func<params string[], bool> IsIt = p1 => 1 > 2; //illegal
8) Intellisense plays well with parameter names of methods (and accordingly you have cool XML documentation available for methods), not so with Action
/Func
. So as far as readability is concerned, regular methods win.
9) Action
/Func
have a parameter limit of 16 (not that you can't define your own ones with more) but methods support more than you will ever need.
As to when to use which, I would consider the following:
When you are forced to use one based on any of the above points, then you anyway have no other choice. Point 3 is the most compelling I find upon which you will have to base your decision.
In most normal cases, a regular method is the way to go. It's the standard way of refactoring a set of common functionality in C# and VB.NET world.
As a rule of thumb, if the function is more than a line, I prefer a method.
If the function has no relevance outside a specific method and the function is too trivial, like a simple selector (Func<S, T>
) or a predicate (Func<bool>
) I would prefer Action
/Func
. For eg,
public static string GetTimeStamp() { Func<DateTime, string> f = dt => humanReadable ? dt.ToShortTimeString() : dt.ToLongTimeString(); return f(DateTime.Now); }
There could be situations where Action
/Func
makes more sense. For instance if you have to build a heavy expression and compile a delegate, its worth doing it only once and caching the compiled delegate.
public static class Cache<T> { public static readonly Func<T> Get = GetImpl(); static Func<T> GetImpl() { //some expensive operation here, and return a compiled delegate } }
instead of
public static class Cache<T> { public static T Get() { //build expression, compile delegate and invoke the delegate } }
In the first case when you call Get
, GetImpl
is executed only once, where as in the second case, (expensive) Get
will be called every time.
Not to forget anonymous method itself will have certain limits unrelated to Func/Action
, making the use little different. Also see this for a related question.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With