Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Action/Func vs Methods, what's the point?

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?

like image 673
James P. Wright Avatar asked Oct 03 '11 02:10

James P. Wright


People also ask

What are Func and Action Why do we use?

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.

What is the point of func in C#?

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.

Is there any difference between action and function?

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.

Could you explain the difference between func vs Action vs predicate?

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.


1 Answers

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:

  1. 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.

  2. 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.

  3. As a rule of thumb, if the function is more than a line, I prefer a method.

  4. 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); } 
  5. 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.

like image 154
nawfal Avatar answered Oct 08 '22 19:10

nawfal