Action、Func和Predicate代理 - C#

5

我正在学习WPF/MVVM,试图理解Action<T>Func<T>Predicate<T>委托之间的区别。

我知道Action<T>Func<T>都可以接受0到1个或多个参数,而Func<T>返回一个值,而Action<T>则不返回任何值。

至于Predicate<T>——我一无所知。

因此,我提出了以下问题:

  1. Predicate<T>是什么?(欢迎提供示例!)
  2. 如果Action<T>不返回任何值,那么只使用void(或任何其他类型,如果我们谈论的是Func<T>)是否更简单?

请避免在您的答案中使用LINQ/List示例。
我已经看过它们了,但它们只会使问题更加混淆,因为让我“感兴趣”的代码与它们没有任何关系(我想!)。
因此,我想使用我熟悉的代码来获得答案。

以下是代码:

public class RelayCommand : ICommand
{
    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;

public RelayCommand(Action<object> execute)
    : this(execute, null)
{
}

public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
    if (execute == null)
        throw new ArgumentNullException("execute");

    _execute = execute;
    _canExecute = canExecute;
}

[DebuggerStepThrough]
public bool CanExecute(object parameters)
{
    return _canExecute == null ? true : _canExecute(parameters);
}

public event EventHandler CanExecuteChanged
{
    add { CommandManager.RequerySuggested += value; }
    remove { CommandManager.RequerySuggested -= value; }
}

public void Execute(object parameters)
{
    _execute(parameters);
}
}

注意:
我删除了注释以避免超长的代码块。
完整代码可在此处找到。

非常感谢您的帮助!谢谢! :)

附言:请不要把我指向其他问题。我确实尝试过搜索,但我找不到简单到我能理解的东西。


3
Predicate 必须返回一个布尔值。我会指引你到另一个问题:https://dev59.com/L3I-5IYBdhLWcg3wta_w - Rotem
6个回答

9

Predicate<T> 是一个委托,它接受一个 T 并返回一个 bool 值。
它与 Func<T, bool> 是完全等效的。

不同之处在于,在 .Net 2.0 中添加了 Predicate<T>,而所有 Func<*> 委托都是在 .Net 3.5 中添加的。(除了带有 >8 个参数的委托,这些委托是在 .Net 4.0 中添加的)

List<T> 中的类 LINQ 方法(FindAll()TrueForAll() 等)采用 Predicate<T> 格式。

回答你的第二个问题,void 不能用作通用参数。


1
我明白了。现在我觉得我更好地理解它了...总而言之,例如Predicate<T> where T=int等同于public delegate bool Delegate(int x),对吗?(= Predicate没有任何特殊功能...) - Asaf

1
Func<T,bool> and Predicate<T> 

倾向于相同的委托。 但是Predicate有点传统,因为在没有Func或Action的时候,Predicate就是一个委托类型。 如果您查看Array、List等类的FindAll/Find方法, 它们使用Predicate。Predicate只返回bool,但Func可以返回您指定的任何类型,因此也可以返回bool。


1

实际上,在LINQ中没有任何地方使用Predicate<T> - SLaks
@SLaks,我已经检查并更新了我的理解和答案。谢谢。 - Tilak
谢谢。在您提供的示例中,list.Select(x => x.SomeProperty) 被介绍为 Func 的一种可能用法。这里如何使用 Func?我也找不到关于 .Select() 的用法说明... - Asaf
x=> x.SomePropertyFunc<T,U> 的一个例子,其中 U-> x.SomeProperty 的类型,T-> x 的类型。 - Tilak

1
“Predicate”是一个函数,它接受一个参数并返回布尔值,例如“x > 20”。
“Action”被定义为返回void的委托。有人可能会问为什么有两种类型的委托,但这只是设计的结果。另一种方法是使用返回不执行任何操作的“Unit”的“Func”。如果“Action”不返回任何内容,使用“void”或其他类型是否更简单?

因此,从本质上讲,你可以说Action是用于 public delegate void Name(type paramName) 的通用委托? - Asaf

0

Predicate是一个委托,它接受T并返回布尔值,本质上它是一个过滤函数。这就是你大多数时候会用到它的地方。

如果您使用Linq的Where()扩展方法,您将看到它接收一个Predicate委托作为参数,此外,您可以使用Predicates创建更复杂的过滤方法,如表达式,并动态地组合多个Predicate委托,使用AND或OR条件等等。

例如,我有一个要求,在WPF中构建报告页面,用户可以动态选择多个参数来自定义报告页面的内容,在这种情况下,我为所选过滤选项(日期时间间隔、布尔值、必须包含在所选字段中的特定字符串等)创建了Predicates,然后组合谓词并将它们编译成表达式,我后来用于过滤我向用户显示的数据集合。


编辑:查看这个 - 为什么要使用 Func<T,bool> 而不是 Predicate<T>?

简而言之:编码指南规定不再使用 Predicates,改用 Func 。


实际上,所有的LINQ方法都需要Funcs或Actions。谓词没有额外的组合能力。 - SLaks
@SLaks 是的,但是谓词确实是一个 Func<T,bool>,在 Where 扩展方法的文档中,您可以看到该参数被称为 Predicate - http://msdn.microsoft.com/en-us/library/bb534803.aspx - dutzu
他在询问 Predicate<T> _类型_,与 LINQ 没有任何关系。 - SLaks

-1
Func和Action的区别在于是否需要委托返回值(使用Func)或不需要(使用Action)。
在LINQ中,Func可能是最常用的 - 例如,在投影中:
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.BeginInvokeDispatcher.BeginInvoke 这样的东西。

Predicate 实际上只是一种特殊情况下的 Func<T, bool>,在所有 Func 和大多数 Action 委托出现之前就已经被引入了。我猜测,如果我们已经拥有了它们各种形式的 FuncAction,那么就不必再引入 Predicate...虽然它确实赋予了委托使用的某种意义,而 FuncAction 则用于广泛不同的目的。

Predicate 主要用于 List<T> 中的方法,例如 FindAllRemoveAll


你只是复制了别人的答案... 你至少可以链接到它或者给作者一些功劳... - Asaf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接