Why is Action/Func better than a regular Method in .Net?
Asked Answered
C

5

15

I much prefer using an Action or a Func if I need a quick reusable piece of code, however others on my team don't like them or understand them.
At the moment my only real argument is about preference and more up to date code practices, but those are just bad arguments.

Why is it better to do this:

Action<FormView,String> hideControl = (form,name) => {
    var button = form.GetControl<Button>(name);
    if (button != null)
        button.Visible = false;
}

than:

public static void HideControl<T>(this FormView form, string name) where T : Control
{
    var button = form.GetControl<Button>(name);
    if (button != null)
        button.Visible = false;
}

?

Can anyone give me solid concrete arguments/examples?

Cross answered 9/12, 2011 at 17:56 Comment(9)
You haven't shown how you're using either the delegate or the method.Hypotonic
Did you mean to use GetControl<T>(name) in your 2nd example?Haemostat
1) I don't see why the second example has a generic parameter T, it does not appear to be used. 2) Show how the action/method is being used. 3) You are asking us to take your side. Would you be willing to accept an answer that disagreed with you? If that is the case, you should edit your question to be more neutral.Ianteen
Gosh. I suppose the 'others' on your team are like me, that is: too old!. BTW, your code only compiles on 'recent' C#/.NET.Marylyn
Why is it better? Well, it's not...Iaria
Yes obviously the 2nd example meant to use T instead of Button. Sorry for the typo. This was just a generic quick example. They would both be used inside of a method that needs to duplicate that code 5-10 times for various controls.Cross
For reference sake, I gladly welcome differing viewpoints. Func/Action are tools that I have only recently adopted and from what I have heard/read about them, they are "the future". I prefer them when I need a quick piece of reusable code, but I know that it's a preference. I should have asked ARE they better, not WHY are they better.Cross
@JamesP.Wright, they are definitely not the future when put up against actual methods. In terms of readability and documentation, they fail pretty hard. They are useful used as callbacks/LINQ expressions/predicates etc, but as a replacement for functions? Hell no.Haemostat
Both look like reuse abuse to me. If you want to set MyForm.MyButton.Visible, just do it. Silently doing nothing because there is no control MyButton, or MyButton isn't a button is a bug waiting to happen. If you want loads of things to happen, extend, if you have options that can be accessed from more than one control (e.g. menu and button), write a class. Wouldn't get past peer review from me.Superhuman
C
38

There are two sides to your question: style and performance.

For code style, using delegates makes things a little messy. There is no function name associated with the body of code (anonymous method), argument types are inferred, and when overused this can lead to large function blocks containing lots of smaller independent chunks of code in delegates. It's not pretty to look at, it can be hard to figure out what the code is actually doing, and it's hard to find what you're looking for.

For performance, delegates introduce an indirection that is not as fast to execute as a plain old method. The difference is small, but when used to excess it could become noticeable.

Any tool has appropriate and excessive uses. It's appropriate to use Action or Func for a callback parameter when you want to pass a callback routine into a function. Using Action or Func as a replacement for declaring functions in general is a misuse, IMO.

Cisneros answered 9/12, 2011 at 18:8 Comment(5)
+1 for "replacement for declaring functions in general is a misuse".Felicle
Can you cite some proof for "delegates introduce an indirection that is not as fast to execute as a plain old method" please?Cross
Action/Func are implemented as delegates. Delegates are implemented in IL as compiler-generated classes with an Invoke() method. Calling foo() when foo is a delegate actually compiles down to calling foo.Invoke(), which in turn calls the destination code. If foo is an actual method instead of a delegate, calling foo() calls directly to the destination code with no Invoke() intermediate. See ILDASM for proof.Cisneros
"For performance, delegates introduce an indirection " Any good references, unit tests, studies about it?Crushing
@Crushing ECMA 335, Part II 14.6. ecma-international.org/publications/standards/Ecma-335.htmCisneros
F
23

The short answer is that, in general, it is not better. I agree with your team mates.

I don't think your question is the right one. Rather than asking why is it better (believe me it is not in most cases), you might ask WHEN is it better.

Now, there are of course times where they are extremely useful, like in LINQ when methods take in a Func, writing a quick lambda is great.

This is far more readable and maintainable:

var myQuery = Customers.Where(x => x.ID == 3).First();

than the alternative:

public bool FilterByID3(Customer cust)
{
  return cust.ID == 3;
}

    var myQuery = Customers.Where(FilterByID3).First();

In most other cases, it is much more readable/maintainable to use functions.

Felicle answered 9/12, 2011 at 18:0 Comment(1)
+1 from me. I find functions more readable. Also, how do document-generators handle actions? Do they?Haemostat
I
11

Why is it better to do this

It's not better. In that case I don't see any advantages in doing this rather than writing a real method. And if you can't either, I don't understand why you're so sure it's better.

Avoid writing long anonymous methods (and by long, I mean more than one or two lines), it just makes the code less readable.

There are however some cases where it can be useful to use an anonymous method: closures. If you need to capture a local variable, then anonymous methods are the way to go. But even then, don't write a long piece of code in it: just call a real method to which you pass the captured variable as a parameter.

Iaria answered 9/12, 2011 at 18:12 Comment(0)
B
10

In general I agree with the other answerers: Blindly replacing function definitions with Action/Func is not a good thing. Action and Func are not the future of .NET. They are a tool which is very useful but like any tool can be misused.

So if you tend to write code like this

class SomeClass {
    Action<...> a1 = (..) => {};
    Func<...> f1 = (..) => {};
    Action<...> a2 = (..) => {};
    ...
}

That is certainly not a good thing.

If you do this a lot:

  void SomeMethod()
  {
      Action<..> a = (..) => {};
      ...
      a();
  }

then this is actually a good way of encapsulating a little helper method without polluting the class.

To argue your specific case: If hideControl is only used in a very specific case the private helper method would be preferred. If it is required for a lot of FormViews then the extension method makes more sense. Extension methods are also a tool which can be misused as it can lead to pollution of the public interface for a class. Although you can limit it through the use of namespaces.

I usually go by this guideline: If you require a helper method which is useful in a lot of places and situations and can be made fairly generic I create an extension method. If it is a helper method which is required for a specific class but in a several places (methods) in that class then I create a private method. If it is a helper which I only need in one specific place then I make it a Action/Func inside that method.

Bitty answered 9/12, 2011 at 22:16 Comment(0)
Z
7

Pros

  • Closures
    • This does not help your case though.
  • Super-private methods -- only the defining method can call it.
    • This is easily countered with the Single Responsibility Principle though. You're likely combining what should be a different class in an entire method.
  • Callbacks
    • These can also easily be methods.

Cons

  • Readability is lessened, in my opinion, because of the excess indentation (I'm not a fan).
  • Debugging becomes a little harder because your call stack is less intuitive especially when you have multiple Func/Action's defined.

You'll have to over come the cons in your environment.

I'm curious about your "more up-to-date coding practice" argument. Just because you can do this as much as possible doesn't mean you should.

Zamarripa answered 9/12, 2011 at 18:23 Comment(1)
+1 from me also. Whilst they are more modern, as you and others answerers have pointing out, they are far from a replacement - the "more up-to-date coding practice" argument is non-existent as far as I can see.Haemostat

© 2022 - 2024 — McMap. All rights reserved.