Why is Action/Func better than a regular Method in

2020-02-23 02:42发布

问题:

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?

回答1:

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.



回答2:

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.



回答3:

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.



回答4:

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.



回答5:

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.