Я думаю, что другие ответы здесь говорят о том, что такое Action
/ Func
и как его использовать.Я постараюсь ответить, как выбрать между Action
/ Func
и методом.Сначала различия:
1) С точки зрения производительности, делегаты медленнее, чем прямые вызовы методов , но это настолько незначительно, что беспокоиться об этомплохая практика.
2) Методы могут иметь перегрузки (одинаковые имена функций с разными сигнатурами), но не делегаты Action
/ Func
, поскольку они объявлены как переменные и по правилам C #вы не можете иметь две переменные с одинаковыми именами в данной области.
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) Следовательно, Action
/ Func
переназначаются и могут указывать на любую функцию, тогда какметоды, однажды скомпилированные, остаются неизменными навсегда.Семантически неправильно использовать Func/Action
, если метод, на который он указывает, никогда не изменяется во время выполнения.
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) Вы можете указать ref
/ out
параметры длянормальные методы.Например, вы можете иметь
bool IsIt(out string p1, ref int p2) { return 1 > 2; } //legal
Func<out string, ref int, bool> IsIt; //illegal
5) Вы не можете ввести новый параметр универсального типа для Action
/ Func
(они, кстати, уже являются универсальными, но аргументы типа могутбыть только известным типом или типами, указанными в родительском методе или классе), в отличие от методов.
bool IsIt<A, R>() { return 1 > 2; } //legal
Func<bool> IsIt<A, R> = () => 1 > 2; //illegal
6) Методы могут иметь необязательные параметры, а не Action
/ Func
.
bool IsIt(string p1 = "xyz") { return 1 > 2; } //legal
Func<string, bool> IsIt = (p1 = "xyz") => 1 > 2; //illegal
7) У вас может быть ключевое слово params
для параметров метода, а не Action
/ Func
.
bool IsIt(params string[] p1) { return 1 > 2; } //legal
Func<params string[], bool> IsIt = p1 => 1 > 2; //illegal
8) Intellisense хорошо работает с именами параметров методов (и, соответственно, у вас есть отличная документация XML для методов), но с Action
/ Func
это не так.Что касается читабельности, то обычные методы выигрывают.
9) Action
/ Func
имеют предел параметра 16 (не то, что вы не можете определить свои собственные)с более), но методы поддерживают больше, чем вам когда-либо понадобится.
Что касается того, когда использовать, я бы рассмотрел следующее:
Если вы вынуждены использовать один из указанных выше пунктов, у вас все равно не останется другого выбора. Точка 3 - это наиболее убедительный вариант, который я считаю основанным на вашем решении.
В большинстве обычных случаев рекомендуется использовать обычный метод.Это стандартный способ рефакторинга набора общих функций в мире C # и VB.NET.
Как правило, если функция больше строки, я предпочитаю метод.
Если у функции нет релевантности вне определенного метода и она слишком тривиальна, как простой селектор (Func<S, T>
) или предикат (Func<bool>
), я бы предпочелAction
/ Func
.Например,
public static string GetTimeStamp()
{
Func<DateTime, string> f = dt => humanReadable
? dt.ToShortTimeString()
: dt.ToLongTimeString();
return f(DateTime.Now);
}
Могут быть ситуации, когда Action
/ Func
имеет больше смысла.Например, если вам нужно создать тяжелое выражение и скомпилировать делегат, стоит сделать это только один раз и кэшировать скомпилированный делегат.
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
}
}
вместо
public static class Cache<T>
{
public static T Get()
{
//build expression, compile delegate and invoke the delegate
}
}
В первом случае, когда вы звоните Get
, GetImpl
выполняется только один раз, где, как и во втором случае, (дорого) Get
будет вызываться каждый раз.
Не забывать, что сам анонимный метод будет иметь определенные ограничения , не связанные с Func/Action
, что делает использование немного другим,Также см. по этому вопросу.