С помощью реальных примеров и их использования кто-то может помочь мне понять:
- Когда нам нужен делегат Func?
- Когда нам нужен делегат Action?
- Когда нам нужен делегат Predicates?
С помощью реальных примеров и их использования кто-то может помочь мне понять:
Разница между 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
.
Действие - это делегат (указатель) к методу, который принимает ноль, один или несколько входных параметров, но ничего не возвращает.
Func - это делегат (указатель) к методу, который принимает нуль, один или несколько входных параметров и возвращает значение (или ссылку).
Предикат - это особый вид Func, который часто используется для сравнения.
Хотя широко используется с Linq, Action и Func - понятия, логически независимые от Linq. С++ уже содержал базовую концепцию в виде типизированных указателей функций.
Вот небольшой пример для 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;
}
}
Func - когда вам нужен делегат для функции, которая может принимать или не принимать параметры и возвращает значение. Наиболее распространенным примером будет Select from LINQ:
var result = someCollection.Select( x => new { x.Name, x.Address });
Действие - когда вам нужен делегат для функции, которая может принимать или не принимать параметры и не возвращает значение. Я часто использую их для анонимных обработчиков событий:
button1.Click += (sender, e) => { /* Do Some Work */ }
Предикат - когда вам нужна специализированная версия Func, которая оценивает значение по набору критериев и возвращает логический результат (true для совпадения, false в противном случае). Опять же, они часто используются в LINQ для таких вещей, как:
var filteredResults =
someCollection.Where(x => x.someCriteriaHolder == someCriteria);
Я просто дважды проверил, и оказалось, что LINQ не использует предикаты. Не уверен, почему они приняли это решение... но теоретически это все еще ситуация, когда Предикат подойдет.