С реальными примерами и их использованием, может кто-нибудь помочь мне понять:
Func vs. Action vs. Predicate
Ответы (3)
Разница между Func
и Action
заключается просто в том, хотите ли вы, чтобы делегат возвращал значение (используйте Func
) или нет (используйте Action
).
Func
, вероятно, наиболее часто используется в LINQ - например, в проекциях:
list.Select(x => x.SomeProperty)
или фильтрация:
list.Where(x => x.SomeValue == someOtherValue)
или выбор ключа:
list.Join(otherList, x => x.FirstKey, y => y.SecondKey, ...)
Action
чаще используется для таких вещей, как List<T>.ForEach
: выполнить заданное действие для каждого элемента в списке. Я использую его реже, чем Func
, хотя я действительно иногда использую версию без параметров для таких вещей, как Control.BeginInvoke
и Dispatcher.BeginInvoke
.
Predicate
- это просто специальный корпус Func<T, bool>
, введенный до того, как пришли все Func
и большинство Action
делегатов. Я подозреваю, что если бы у нас уже были Func
и Action
в их различных обличьях, Predicate
не был бы представлен ... хотя он действительно придает определенный смысл использованию делегата, тогда как Func
и Action
используются в самых разных целях.
Predicate
в основном используется в List<T>
для таких методов, как FindAll
и RemoveAll
.
Predicate
в сигнатуре функции. Это показывает, что переданный метод принимает решение, а не просто возвращает код успеха или другой вид bool
.
- person Ron Warholic; 30.11.2010
Predicate<T>
или Func<T,bool>
? Мне нравится выразительность Predicate
, но я видел рекомендации и для Func
.
- person CodesInChaos; 30.11.2010
Func
повсюду, но это, вероятно, для согласованности, учитывая, что многие методы, принимающие Func<T,bool>
в качестве предиката, также имеют перегрузку, принимающую Func<T,int,bool>
в качестве индексированного предиката.
- person Jon Skeet; 30.11.2010
Predicate
s в некоторых случаях использования и Func<…,bool>
s в других для передачи смысла. По совпадению, можно сказать, что разница между вашим предпоследним абзацем и комментарием @Ron подобна разнице между использованием Func<T,bool>
и Predicate<T>
.
- person Slipp D. Thompson; 28.01.2015
Func<T,bool>
там, где ему нужен Predicate<T>
, но не наоборот: не может преобразовать из System.Predicate ‹int› в System. Func ‹int, bool› '.
- person Mark Hurd; 26.07.2015
Where<T>(this s, Predicate p)
для нескольких случаев, когда у вас уже есть Predicate
для использования в предложении Where
, внезапно все ваши предложения Where
будут соответствовать этому новому методу расширения (включая тот, который сейчас рекурсивно используется внутри, ожидая, что он продолжит для ссылки на существующий метод расширения Where
:-().
- person Mark Hurd; 26.07.2015
Func<T, bool>
, либо в Predicate<T>
, и ссылкой на существующий Predicate<T>
. Чтобы вызвать исходный метод расширения, просто вызовите его как статический метод: Enumerable.Where(...)
- person Jon Skeet; 26.07.2015
Dim IsEven = Function(x As Integer) ((x And 1) = 0)
. Эквивалент var IsEven = (int x) => ((x & 1) == 0);
жалуется: невозможно присвоить лямбда-выражение неявно типизированной локальной переменной.
- person Mark Hurd; 26.07.2015
queryable.Where(IsEven)
только IEnumerable
использует .Where
расширения, предоставленные Linq, но когда я предоставляю свои собственные Predicate
расширения (одно для IEnumerable
и одно для IQueryable
), это IQueryable
.
- person Mark Hurd; 26.07.2015
Действие - это делегат (указатель) на метод, который принимает ноль, один или несколько входных параметров, но ничего не возвращает.
Func - это делегат (указатель) на метод, который принимает ноль, один или несколько входных параметров и возвращает значение (или ссылку).
Предикат - это особый вид Func, который часто используется для сравнений.
Хотя Action и Func широко используются с Linq, они логически независимы от Linq. C ++ уже содержал базовую концепцию в виде указателей на типизированные функции.
Вот небольшой пример для Action и Func без использования Linq:
class Program
{
static void Main(string[] args)
{
Action<int> myAction = new Action<int>(DoSomething);
myAction(123); // Prints out "123"
// can be also called as myAction.Invoke(123);
Func<int, double> myFunc = new Func<int, double>(CalculateSomething);
Console.WriteLine(myFunc(5)); // Prints out "2.5"
}
static void DoSomething(int i)
{
Console.WriteLine(i);
}
static double CalculateSomething(int i)
{
return (double)i/2;
}
}
myAction(123);
. Вам не нужно использовать .Invoke()
- person romar; 22.12.2013
Func - если вам нужен делегат для функции, которая может принимать или не принимать параметры и возвращать значение. Наиболее распространенный пример - Выбрать из LINQ:
var result = someCollection.Select( x => new { x.Name, x.Address });
Действие - если вам нужен делегат для функции, которая может принимать или не принимать параметры и не возвращать значение. Я часто использую их для анонимных обработчиков событий:
button1.Click += (sender, e) => { /* Do Some Work */ }
Предикат - если вам нужна специализированная версия Func, которая оценивает значение по набору критериев и возвращает логический результат (true для совпадения, false в противном случае). Опять же, они довольно часто используются в LINQ для таких вещей, как Where:
var filteredResults =
someCollection.Where(x => x.someCriteriaHolder == someCriteria);
Я только что дважды проверил, и оказалось, что LINQ не использует предикаты. Не знаю, почему они приняли это решение ... но теоретически это все еще ситуация, в которой предикат подойдет.
Func
или Action
используются делегаты с осмысленными именами.
- person Sam; 14.06.2013