Почему Action / Func лучше, чем обычный метод в .Net? - PullRequest
11 голосов
/ 09 декабря 2011

Я очень предпочитаю использовать Action или Func, если мне нужен быстро повторяющийся фрагмент кода, однако другие члены моей команды их не любят или не понимают.
На данный момент мой единственный реальный аргумент - о предпочтениях иболее современные практики кода, но это просто плохие аргументы.

Почему лучше сделать это:

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

чем:

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;
}

?

Может кто-нибудь дать мне конкретные конкретные аргументы / примеры

Ответы [ 5 ]

30 голосов
/ 09 декабря 2011

У вашего вопроса есть две стороны: стиль и производительность.

Для стиля кода использование делегатов делает вещи немного беспорядочными. С телом кода не связано имя функции (анонимный метод), типы аргументов выводятся, и при чрезмерном использовании это может привести к большим функциональным блокам, содержащим множество меньших независимых фрагментов кода в делегатах. На это не приятно смотреть, может быть трудно понять, что на самом деле делает код, и трудно найти то, что вы ищете.

Для повышения производительности делегаты вводят косвенное указание, которое не так быстро выполняется, как обычный старый метод. Разница невелика, но при превышении она может стать заметной.

Любой инструмент имеет подходящее и чрезмерное использование. Целесообразно использовать Action или Func для параметра обратного вызова, когда вы хотите передать функцию обратного вызова в функцию. Использование Action или Func в качестве замены для объявления функций в целом является неправильным использованием, IMO.

17 голосов
/ 09 декабря 2011

Краткий ответ: вообще не лучше. Я согласен с вашими товарищами по команде.

Я не думаю, что ваш вопрос правильный. Вместо того, чтобы спрашивать, почему это лучше (поверьте мне, это не так в большинстве случаев), вы можете спросить, КОГДА это лучше.

Теперь, конечно, бывают случаи, когда они чрезвычайно полезны, например, в LINQ, когда методы принимают Func, писать быструю лямбду просто замечательно.

Это гораздо удобочитаемее и удобнее в обслуживании:

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

чем альтернатива:

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

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

В большинстве других случаев гораздо удобнее читать / поддерживать функции.

9 голосов
/ 09 декабря 2011

Почему это лучше сделать

Это не лучше. В этом случае я не вижу никаких преимуществ в этом, чем в написании реального метода. И если вы тоже не можете, я не понимаю, почему вы так уверены, что лучше.

Избегайте написания длинных анонимных методов (и под длинным я имею в виду более одной или двух строк), это просто делает код менее читабельным.

Однако в некоторых случаях полезно использовать анонимный метод: замыкания. Если вам нужно захватить локальную переменную, тогда вам нужно использовать анонимные методы. Но даже тогда не пишите в нем длинный кусок кода: просто вызовите реальный метод, которому вы передаете захваченную переменную в качестве параметра.

8 голосов
/ 10 декабря 2011

В целом я согласен с другими ответчиками: слепая замена определений функций на Action / Func - это не очень хорошая вещь.Action и Func не являются будущим .NET.Это инструмент, который очень полезен, но, как и любой инструмент, может использоваться неправильно.

Так что, если вы склонны писать такой код

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

Это, конечно,хорошая вещь.

Если вы делаете это много:

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

, тогда это действительно хороший способ инкапсуляции небольшого вспомогательного метода без загрязнения класса.

Чтобы аргументировать ваш конкретный случай: если hideControl используется только в очень конкретном случае, предпочтителен частный вспомогательный метод.Если это требуется для большого числа FormViews, тогда метод расширения имеет больше смысла.Методы расширения также являются инструментом, которым можно злоупотреблять, поскольку это может привести к загрязнению общедоступного интерфейса для класса.Хотя вы можете ограничить это с помощью использования пространств имен.

Я обычно придерживаюсь этого правила: если вам требуется вспомогательный метод, который полезен во многих местах и ​​ситуациях и может быть сделан достаточно общим, я создаю расширениеметод.Если это вспомогательный метод, который требуется для определенного класса, но в нескольких местах (методах) в этом классе, тогда я создаю закрытый метод.Если это помощник, который мне нужен только в одном конкретном месте, тогда я делаю его Action / Func внутри этого метода.

7 голосов
/ 09 декабря 2011

Плюсы

  • Закрытия
    • Это не поможет вашему делу.
  • Только супер-приватные методыопределяющий метод может вызвать его.
    • Это легко противоречит принципу единой ответственности.Вы, вероятно, комбинируете то, что должно быть другим классом во всем методе.
  • Обратные вызовы
    • Это также могут быть методы.

Минусы

  • На мой взгляд читаемость снижена из-за избыточного отступа (я не фанат).
  • Отладка становится немного сложнее, потому что ваш стек вызовов менее интуитивно понятен, особенно когда у вас есть несколько Func / Action, определенных.

Вам придется преодолетьминусы в вашей среде.

Мне любопытен ваш аргумент "более современной практики кодирования".То, что вы можете делать это как можно больше, не означает, что вы должны .

...