C# 委托谓词
上次修改时间:2023 年 1 月 16 日
在本文中,我们将展示如何在 C# 中使用谓词。 使用谓词,我们可以创建更清晰、更易读的代码。
谓词
谓词 的一般含义是指关于某事物的陈述,该事物要么为真,要么为假。在编程中,谓词表示返回布尔值的单参数函数。
C# 委托谓词
C# 中的谓词是通过委托实现的。 Predicate
委托表示定义一组条件并确定指定的对象是否符合这些条件的方法。
C# 谓词示例
以下示例创建一个简单的 C# 谓词。
List<int> data = [1, -2, 3, 0, 2, -1]; var predicate = new Predicate<int>(isPositive); var filtered = data.FindAll(predicate); Console.WriteLine(string.Join(",", filtered)); bool isPositive(int val) { return val > 0; }
在此示例中,谓词用于过滤掉正值。
var predicate = new Predicate<int>(IsPositive);
定义了一个谓词委托;它将 IsPositive
方法作为参数。
var filtered = data.FindAll(predicate);
我们将谓词传递给列表的 FindAll
方法,该方法检索谓词返回 true 的所有值。
bool IsPositive(int val) { return val > 0; }
对于所有大于零的值,IsPositive
返回 true。
$ dotnet run 1,3,2
带有匿名方法的 C# 谓词
以下示例将一个匿名方法传递给委托。
List<int> data = [1, -2, 3, 0, 2, -1]; Predicate<int> isPositive = delegate(int val) { return val > 0; }; var filtered = data.FindAll(isPositive); Console.WriteLine(string.Join(",", filtered));
该示例使用 delegate
关键字来定义一个匿名方法。
带有 Lambda 表达式的 C# 谓词
C# Lambda 表达式简化了 C# 谓词的创建。 Lambda 表达式是使用 =>
lambda 声明运算符创建的。
List<string> words = [ "falcon", "wood", "tree", "rock", "cloud", "rain" ]; Predicate<string> hasFourChars = word => word.Length == 4; var words2 = words.FindAll(hasFourChars); Console.WriteLine(string.Join(',', words2));
在此示例中,我们找出所有包含四个字母的单词。
$ dotnet run wood,tree,rock,rain
带有 Exists 的 C# 谓词
列表的 Exists
方法确定列表是否包含与指定谓词定义的条件匹配的元素。
List<string> words = [ "sky", "", "club", "spy", "silk", "summer", "war", "cup", "cloud", "coin", "small", "terse", "", "snow", "snail", "see"]; Predicate<string> pred = string.IsNullOrEmpty; if (words.Exists(pred)) { Console.WriteLine("There is an empty string"); } else { Console.WriteLine("There is no empty string"); }
我们检查列表中是否存在一些空字符串。
$ dotnet run There is an empty string
带有 RemoveAll 的 C# 谓词
列表的 RemoveAll
方法删除所有与指定谓词定义的条件匹配的元素。
List<string> words = ["sky", "town", "club", "spy", "silk", "snail", "war", "cup", "cloud", "coin", "small", "terse"]; Predicate<string> HasThreeChars = word => word.Length == 3; words.RemoveAll(HasThreeChars); Console.WriteLine(string.Join(", ", words));
我们有一个单词列表。 我们删除所有包含三个拉丁字符的单词。
$ dotnet run town, club, silk, snail, cloud, coin, small, terse
C# 谓词多个条件
以下示例使用带有两个条件的谓词。
List<Country> countries = [ new ("Iran", 80840713), new ("Hungary", 9845000), new ("Poland", 38485000), new ("India", 1342512000), new ("Latvia", 1978000), new ("Vietnam", 95261000), new ("Sweden", 9967000), new ("Iceland", 337600), new ("Israel", 8622000) ]; Predicate<Country> p1 = c => c.Name.StartsWith('I'); Predicate<Country> p2 = c => c.Population > 1000_0000; Predicate<Country> CombineAnd = c => p1(c) && p2(c); var result = countries.FindAll(CombineAnd); Console.WriteLine(string.Join(", ", result)); record Country(string Name, int Population);
我们创建一个国家/地区列表。 我们找到所有以“I”开头且人口超过一百万的国家/地区。
Predicate<Country> p1 = c => c.Name.StartsWith('I'); Predicate<Country> p2 = c => c.Population > 1000_0000;
我们定义两个谓词。
Predicate<Country> CombineAnd = c => p1(c) && p2(c);
我们将这两个谓词结合起来。
var result = countries.FindAll(CombineAnd);
我们将组合谓词应用于 FindAll
方法。
$ dotnet run Country { Name = Iran, Population = 80840713 }, Country { Name = India, ...
C# 否定谓词
我们可以创建一个委托来否定已定义的委托。
List<string> words = [ "falcon", "wood", "tree", "rock", "cloud", "rain" ]; Predicate<string> HasFourChars = word => word.Length == 4; Predicate<string> Negate = word => !HasFourChars(word); var words2 = words.FindAll(Negate); Console.WriteLine(string.Join(',', words2)); // Predicate<T> Negate<T>(Predicate<T> predicate) // { // return x => !predicate(x); // }
该示例否定了 HasFourChars
委托。 一个替代解决方案被注释掉了。
$ dotnet run falcon,cloud
这些是长度不是四个字母的单词。
带有 Func 的 C# 谓词
Func
是一种泛型委托类型。 它可以包含 0 到 16 个输入参数,并且必须具有一个返回类型。 Predicate
是 Func
的特例。
List<Person> data = [ new ("John Doe", "gardener"), new ("Robert Brown", "programmer"), new ("Lucia Smith", "teacher"), new ("Thomas Neuwirth", "teacher") ]; ShowOutput(data, r => r.Occupation == "teacher"); void ShowOutput(List<Person> list, Func<Person, bool> condition) { var data = list.Where(condition); foreach (var person in data) { Console.WriteLine($"{person.Name}, {person.Occupation}"); } } record Person(string Name, string Occupation);
该示例创建一个人员列表。 ShowOutput
方法将一个谓词作为第二个参数。 它返回所有作为教师的人员。
带有 Array.FindAll 的 C# 谓词
Array.FindAll
方法检索所有与指定谓词定义的条件匹配的元素。
User[] users = [ new (1, "John", "London", "2001-04-01"), new (2, "Lenny", "New York", "1997-12-11"), new (3, "Andrew", "Boston", "1987-02-22"), new (4, "Peter", "Prague", "1936-03-24"), new (5, "Anna", "Bratislava", "1973-11-18"), new (6, "Albert", "Bratislava", "1940-12-11"), new (7, "Adam", "Trnava", "1983-12-01"), new (8, "Robert", "Bratislava", "1935-05-15"), new (9, "Robert", "Prague", "1998-03-14"), ]; var age = 60; Predicate<User> olderThan = e => GetAge(e) > age; var res = Array.FindAll(users, olderThan); foreach (var e in res) { Console.WriteLine(e); } int GetAge(User user) { var dob = DateTime.Parse(user.DateOfBirth); return (int) Math.Floor((DateTime.Now - dob).TotalDays / 365.25D); } record User(int Id, string Name, string City, string DateOfBirth);
我们获取所有年龄大于 60 岁的用户。
Predicate<User> olderThan = e => GetAge(e) > age;
在谓词定义中,我们使用 GetAge
方法来确定用户的年龄。
var res = Array.FindAll(users, olderThan);
Array.FindAll
方法检索所有与指定谓词定义的条件匹配的元素。
int GetAge(User user) { var dob = DateTime.Parse(user.DateOfBirth); return (int) Math.Floor((DateTime.Now - dob).TotalDays / 365.25D); }
GetAge
方法解析出生日期字符串并计算当前年龄。
$ dotnet run User { Id = 4, Name = Peter, City = Prague, DateOfBirth = 1936-03-24 } User { Id = 6, Name = Albert, City = Bratislava, DateOfBirth = 1940-12-11 } User { Id = 8, Name = Robert, City = Bratislava, DateOfBirth = 1935-05-15 }
C# 泛型 FindAll
接下来,我们定义一个 FindAll
列表扩展方法。
public static class ExtensionMethods { public static List<T> FindAll<T>(this List<T> vals, List<Predicate<T>> preds) { List<T> data = new List<T>(); foreach (T e in vals) { bool pass = true; foreach (Predicate<T> p in preds) { if (!(p(e))) { pass = false; break; } } if (pass) data.Add(e); } return data; } }
FindAll
方法返回满足所有指定谓词的列表元素。
public static List<T> FindAll<T>(this List<T> vals, List<Predicate<T>> preds)
FindAll
方法将泛型谓词函数列表作为参数。 它返回一个经过过滤的泛型列表。
List<Predicate<int>> preds = [e => e > 0, e => e % 2 == 0]; List<int> vals = [-3, -2, -1, 0, 1, 2, 3, 4]; var filtered = vals.FindAll(preds); foreach (var e in filtered) { Console.WriteLine(e); } Console.WriteLine("---------------------"); List<string> words = ["sky", "wrath", "wet", "sun", "pick", "who", "cloud", "war", "water", "jump", "ocean"]; List<Predicate<string>> preds2 = [e => e.StartsWith('w'), e => e.Length == 3]; var filtered2 = words.FindAll(preds2); foreach (var e in filtered2) { Console.WriteLine(e); }
我们定义两个列表:一个整数列表和一个字符串列表。 从整数列表中,我们过滤掉所有正偶数值。 从字符串列表中,我们获取所有以“w”开头且包含三个字母的单词。
$ dotnet run 2 4 --------------------- wet who war
来源
在本文中,我们使用了 C# Predicate
。
作者
列出所有 C# 教程。