我什么时候使用谓词

When do I use a predicate

我了解谓词是什么以及如何创建谓词,但我什么时候使用它?我为什么要使用它?

例如:

Predicate<string> isUpper = s => s.Equals(s.ToUpper());

我为什么要这样做或类似的事情?

谓词可以存储为变量。这意味着它们可以作为参数传递或作为成员变量存储在 class 中。如果您熟悉 strategy pattern 这可以让您做到这一点,但不需要创建一个完整的 class 来封装您的策略。

例如,假设我们在任意整数列表上使用 LINQ。

然后我们可以这样做:

List<int> evenInts = ints.Where(i => i % 2 == 0).ToList();

谓词允许像Where这样的方法存在并被简洁地使用。

我使用过 C# 谓词,它们只是 return 布尔值的委托。 当您搜索一组对象并想要特定的东西时,它们很有用。 它们通常用于允许您在运行时提供逻辑,可以根据需要简单或复杂。

我已经将它与第三方控件 Telerik Treeview 一起使用来搜索特定节点。

Predicate 委托是一种内置的泛型类型委托。此委托在系统命名空间下定义。谓词委托通常用于根据一组条件对某些数据执行搜索操作。它与那些包含一些标准集的方法一起工作,并确定传递的参数是否满足给定的标准。

语法示例:

public delegate bool Predicate <in P>(P obj);

为什么要使用谓词

C# Predicate 的一些优点:

  • 当我们必须过滤掉值列表时,Predicate 委托很有用。
  • 可以为一次性搜索功能内嵌谓词委托。
  • 当我们必须在通用集合中搜索项目时,可以使用谓词委托。
  • 通过使用谓词委托,缩短了代码的长度并返回 true 或 false。
  • 匿名方法,lambda 表达式可以赋值给谓词委托。
  • 谓词委托提供了运行时的逻辑,可以是简单的逻辑也可以是复杂的逻辑

首先,我将总结委托和 lambda 表达式。

代表


在 C# 中,delegates 允许您创建表示函数的类型。换句话说,委托允许您在变量中保存对方法的引用。一旦我们存储了对该方法的引用,我们就可以使用该变量来调用它所引用的方法。所以你间接调用了这个方法。 C#中的“delegate”一词很符合delegate的字面意思。

要存储对方法的引用,您首先需要创建一个兼容的委托:

delegate int MyDelegate(string parameter)

上面的语句创建了一个委托,它可以保存对 return 类型 int 的任何方法的引用,并采用单个 string 作为参数。例如,我正在创建一个简单的 class 和一个演示方法:

class AClass 
{
    public int StringLength(string str) { return str.Length; }
}

创建委托后,您可以像使用类型一样使用它:

AClass obj = new AClass()
MyDelegate d = obj.StringLength

注意我跳过了 StringLength 之后的括号。现在我可以这样做了:

int length = d("Hello");

这将间接调用 obj.StringLength(),它的值 return 将由 d return 编辑并存储在 length 中。

还有更多像 multicast delegates 这样的代表超出了这个答案的范围。

代表为什么强大?

它们可以帮助您像物品一样轻松地传递 functions/methods。您可以将自己的方法传递给 class,它对您的方法一无所知,但稍后会通过委托调用它。这允许您将自定义逻辑嵌入到您一无所知的代码中。

Lambda 表达式


A lambda expression 只不过是一个函数文字。它有助于在不创建新 class 和新方法的情况下快速创建函数。在前面的示例中,我使用方法 StringLength 创建了一个名为 AClass 的 class。您可以看到所有方法主体都由一行组成。使用 lambdas,可以跳过创建 class 和方法,直接指定方法体:

MyDelegate d = str => str.Length;

Predicate<T>代表


Predicate<T>也是一个代表,定义如下:

delegate bool Predicate<T>(T obj)

这是一个带有泛型参数的委托。这允许您向它传递任何类型的参数,该参数将在稍后创建委托变量时指定,但 return 类型始终为 bool。谓词本质上只是一个条件,可以是 truefalse.

关于您的问题,使用谓词,您可以将这样的条件传递给方法,以便该方法可以使用它来检查它是否适用于 class 的私有内容。您基本上是在传递稍后将执行的逻辑。

谓词的一个常见用例是过滤。如果我有一个元素集合,并且我想过滤元素并仅获取条件成立的那些元素,我可以使用 Predicate<T> 参数:


public List<int> Filter(List<int> list, Predicate<int> filter)
{
    public var filteredList = new List<int>();
    foreach (int element in list)
    {
        if (filter(element))
        {
            filteredList.Add(element); //Add to list only if condition holds true for the element
        }
        
    }
}

现在,假设我有一个列表,我只想要偶数和大于 5 的数字,那么我可以简单地这样做:

var numbers = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 }
var evenNumbers = Filter(numbers, element => element % 2 == 0);    // 2, 4, 6, 8
var numbersGreaterThan5 = Filter(numbers, element => element > 5); // 6, 7, 8, 9

实际上,您几乎不必创建自定义 Filter() 方法,因为 System.Linq 已经有一个名为 Where() 的 method/LINQ 运算符可以为您执行此操作。此 Where() 方法的参数不是 Predicate<T>,而是相同的(兼容性方面)Func<T, bool>,它是另一个定义如下的委托:

delegate TResult Func<in T, out TResult>(T arg)

Func<T, bool>Predicate<T> 因此在它们可以引用的方法方面是相同的。此外,您可以使用与谓词相同的签名创建自己的委托。该框架定义了其中的一堆,以使您的生活更轻松。