2010-11-30 4 views
576

С реальными примерами и их использования, может кто-то пожалуйста, помогите мне понять:Func против действий против Predicate

  1. Когда нам нужен Func делегат?
  2. Когда нам нужно делегировать действия?
  3. Когда нам нужен делегат Predicates?
+2

Даже если это дубликат имеет более тщательный обслуживаемого ответ – reggaeguitar

+4

@reggaeguitar Что интересно, что оба принятого ответа от Jon Skeet – rafid059

ответ

743

Разница между 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 чаще используется для таких вещей, как : выполнить n для каждого элемента в списке. Я использую это реже, чем Func, хотя I do иногда используют версию без параметров для таких вещей, как Control.BeginInvoke и Dispatcher.BeginInvoke.

Predicate - только специальный корпус Func<T, bool> действительно, представленный перед всеми Func, и большинство делегатов Action пришли. Я подозреваю, что если бы мы уже Func и Action в их различных формах, Predicate бы не был введен ... хотя делает придает определенное значение для использования делегата, в то время как Func и Action используется для широко разрозненные цели.

Predicate в основном используется в List<T> для таких методов, как FindAll и RemoveAll.

+50

Мне нравится видеть «Predicate» в сигнатуре функции. Он иллюстрирует, что переданный метод принимает решение, а не просто возвращает код успеха или другой тип 'bool'. –

+5

Есть ли какая-либо директива о том, следует ли предпочитать 'Predicate ' или 'Func '? Мне нравится выразительность «Predicate», но я также видел рекомендации для «Func». – CodesInChaos

+3

@ Ron: Да, это в значительной степени то, о чем я говорил в своем предпоследнем абзаце. –

55

Func - Если требуется делегат для функции, которая может или не может принимать параметры и возвращает значение. Наиболее распространенный пример будет выбрать из LINQ:

var result = someCollection.Select(x => new { x.Name, x.Address }); 

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

button1.Click += (sender, e) => { /* Do Some Work */ } 

Predicate - Если вы хотите специализированный вариант Func который берет оценивает значение от набора критериев и возвращает логический результат (правда, на матч, false в противном случае). Опять же, они используются в LINQ довольно часто для таких вещей, как Где:

var filteredResults = 
    someCollection.Where(x => x.someCriteriaHolder == someCriteria); 

Я просто проверил и получается, что LINQ не использует Предикаты. Не знаю, почему они приняли это решение ... но теоретически это все еще ситуация, в которой будет существовать Предикат.

+2

Я знаю, что это старо, но предикат не использовался LINQ, потому что он предшествует Func и Action, которые мы знаем сегодня, а последние два могут быть использованы для достижения того же результата в гораздо лучшем виде. – gparent

+0

@gparent, почему это лучше? Я считаю, что читаемость лучше, если вместо 'Func' или' Action' используются значащие имена делегатов. – Sam

+1

Это зависит от того, как вы используете делегатов, но иногда это имя не так важно и необходимость создавать функции и переменные только для одного использования для меня уменьшает читаемость. – gparent

287

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

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

Predicate - особый вид Func, который часто используется для сравнения.

Хотя широко используется с Linq, Action и Func, понятия логически независимы от Linq. C++ уже содержал базовую концепцию в виде типизированных указателей функций.

Вот небольшой пример действий и 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; 
    } 
} 
+20

Предикат - это делегат, который принимает общие параметры и возвращает bool – Martin

+24

Приятный пример! Обратите внимание, что вы также можете вызвать myAction, просто называя его: 'myAction (123);'. Вам не нужно использовать '.Invoke()' – romar

Смежные вопросы