首页 > 代码库 > C#语法糖之第六篇: 泛型委托- Predicate<T>、Func<T>

C#语法糖之第六篇: 泛型委托- Predicate<T>、Func<T>

今天继续分享泛型委托的Predicate<T>,上篇文章讲了Action委托,这个比Action委托功不一样的地方就是委托引用方法是Bool返回值的方法,Action为无返回值。首先我们看一下它的定义吧:

1 public delegate  bool Predicate<T>(T obj);
View Code

从其定义可以看到,此委托引用一个返回bool 值的方法,在实际开发中,通常使用Predicate<T>委托变量引用一个“判断条件函数”,在判断条件函数内部书写代码表明函数参数所引用的对象应满足的条件,条件满足时,函数返回true.

我们在自己实现一下该委托:

 1 public static class PredicateClass 2  3     { 4  5         public delegate bool PanDuan<T>(T t); 6  7         public static List<T> MyFind<T>(this List<T> tList, PanDuan<T> find) 8  9         {10 11             List<T> newTs = new List<T>();12 13             foreach (T t in tList)14 15             {16 17                 if (find(t))18 19                 {20 21                     newTs.Add(t);22 23                 }24 25             }26 27             return newTs;28 29         }30 31         public static bool 打印学生信息(Student stu)32 33         {34 35             if (stu.Age > 20) return true;36 37             return false;38 39         }40 41         public static bool 打印教师信息(Teacher teacher)42 43         {44 45             if (teacher.Age > 40 && teacher.TeachNum=="001") return true;46 47             return false;48 49         }50 51     }
View Code

调用代码如下:

 1  List<Student> students=new List<Student>(); 2  3             students.Add(new Student{ StuNum = "001",StuName = "zhangsan",Age = 20}); 4  5             students.Add(new Student { StuNum = "002", StuName = "lisi", Age = 21 }); 6  7             students.Add(new Student { StuNum = "003", StuName = "wangwu", Age = 22 }); 8  9             List<Teacher> teacher=new List<Teacher>();10 11             teacher.Add(new Teacher{TeachNum = "004",TeachName = "teacher1",Age = 50});12 13             teacher.Add(new Teacher { TeachNum = "005", TeachName = "teacher2", Age = 51 });14 15             teacher.Add(new Teacher { TeachNum = "006", TeachName = "teacher3", Age = 52 });16 17             Console.WriteLine("原始总数:"+teacher.Count);18 19             List<Teacher> teachers=teacher.MyFind(PredicateClass.打印教师信息);20 21             Console.WriteLine("过滤后总数:"+teachers.Count);22 23             Console.WriteLine("原始总数:" + students.Count);24 25             List<Student> studeList = students.MyFind(PredicateClass.打印学生信息);26 27             Console.WriteLine("过滤后总数:" + studeList.Count);
View Code

输出效果:

 

以上效果可以看出通过自定义泛型委托来判断和过滤一些信息,最后得到过滤后的数据。

以上代码可以简化:

 1 //标准写法 2  3 Console.WriteLine("原始总数:" + teacher.Count); 4  5             List<Teacher> teachers = teacher.MyFind( 6  7                 new PredicateClass.PanDuan<Teacher>(delegate(Teacher t) 8  9                 {10 11                     if (t.Age>21&&t.TeachNum=="001")12 13                     {14 15                         return true;16 17                     }18 19                     return false;20 21                 }));22 23             Console.WriteLine("过滤后总数:" + teachers.Count);24 25 //匿名方法26 27             Console.WriteLine("原始总数:" + teacher.Count);28 29             List<Teacher> teachers1 = teacher.MyFind(30 31                delegate(Teacher t)32 33                 {34 35                     if (t.Age > 21 && t.TeachNum == "001")36 37                     {38 39                         return true;40 41                     }42 43                     return false;44 45                 });46 47             Console.WriteLine("过滤后总数:" + teachers.Count);48 49 //Lambda表达式50 51             Console.WriteLine("原始总数:" + teacher.Count);52 53             List<Teacher> teachers2 = teacher.MyFind(54 55                u=>56 57                {58 59                    if (u.Age > 21 && u.TeachNum == "001")60 61                    {62 63                        return true;64 65                    }66 67                    return false;68 69                });70 71             Console.WriteLine("过滤后总数:" + teachers.Count);
View Code

输出结果:

 

从结果可以看出,这三个方法结果都是一样的。学生类的打印方法跟这个一样,所以在这里不做演示了,只要理解了这个方法以后在看看微软系统内置委托就很容易理解了,在这里用List的FindAll()方法吧:

 1 List<Student> students=new List<Student>(); 2  3             students.Add(new Student{ StuNum = "001",StuName = "zhangsan",Age = 20}); 4  5             students.Add(new Student { StuNum = "002", StuName = "lisi", Age = 21 }); 6  7             students.Add(new Student { StuNum = "003", StuName = "wangwu", Age = 22 }); 8  9             List<Teacher> teacher=new List<Teacher>();10 11             teacher.Add(new Teacher{TeachNum = "004",TeachName = "teacher1",Age = 50});12 13             teacher.Add(new Teacher { TeachNum = "005", TeachName = "teacher2", Age = 51 });14 15             teacher.Add(new Teacher { TeachNum = "006", TeachName = "teacher3", Age = 52 });16 17             Console.WriteLine("原始总数:"+teacher.Count);18 19             List<Teacher> tt=teacher.FindAll(new Predicate<Teacher>(delegate(Teacher t)20 21                 {22 23                     if (t.TeachNum == "004") return true;24 25                     return false;26 27                 }));28 29             Console.WriteLine("原始总数:"+tt.Count);
View Code

输出结果:

 

在分享一下Func<T>,个人觉得这个也是这三个中功能最强大的,我先看看微软官网的解释:

Func<T,TResut>:封装一个具有一个参数并返回 TResult 参数指定的类型值的方法。

我们在上面的例子上在扩展,因为上面委托的方法返回值是bool类型,如果需要返回指定类型的话,上面的委托就不能满足要求了,所以用Func〈T〉很容易实现的,比如我们在上面的老师类中筛选年龄,组成一个新的集合:

具体代码如下:

1 List<int> AgeList=teacher.Select(new Func<Teacher, int>(delegate(Teacher t)2 3                 {4 5                     return t.Age;6 7                 })).ToList();8 9             AgeList.ForEach(u => { Console.WriteLine(u);});
View Code

输出结果:

以上结果可以看出来把老师的年龄打印出来了,具体写法应该不用再解释了吧,因为这个写法上面都不止一次的写了。我们在把匿名方法简化成Lambda表达式:

1 List<int> AgeList=teacher.Select(t=>2 3                 {4 5                     return t.Age;6 7                 }).ToList();8 9             AgeList.ForEach(u => { Console.WriteLine(u);});
View Code

我们在写一个返回自定义类型的例子:

把上面的例子在扩展为返回满足要求的老师集合:

 1 List<Student> students=new List<Student>(); 2  3             students.Add(new Student{ StuNum = "001",StuName = "zhangsan",Age = 20}); 4  5             students.Add(new Student { StuNum = "002", StuName = "lisi", Age = 21 }); 6  7             students.Add(new Student { StuNum = "003", StuName = "wangwu", Age = 22 }); 8  9             List<Teacher> teacher=new List<Teacher>();10 11             teacher.Add(new Teacher{TeachNum = "004",TeachName = "teacher1",Age = 20});12 13             teacher.Add(new Teacher { TeachNum = "005", TeachName = "teacher2", Age = 51 });14 15             teacher.Add(new Teacher { TeachNum = "006", TeachName = "teacher3", Age = 52 });
View Code
 1 List<Student> tt = teacher.Select( 2  3                 new Func<Teacher, Student>( 4  5                     delegate(Teacher u) 6  7                         { 8  9                             Student e = new Student();10 11                             if (u.Age < 23)12 13                             {14 15                                 e.StuName = u.TeachName;16 17                                 e.Age = u.Age;18 19                                 e.StuNum = u.TeachNum;20 21                             }22 23                             else24 25                             {26 27                                 return null;28 29                             }30 31                             return e;32 33                         }34 35                 )36 37             ).ToList();38 39             tt.ForEach(u =>40 41                 {42 43                     if (u != null) Console.WriteLine("姓名:"+u.StuName +"年龄:"+ u.Age);44 45                 });
View Code

输出结果为:

这个就是年龄为小于23的老师赋值给学生类,并打印的例子,我在这里把逻辑写成匿名方法了,如朋友们觉得匿名方法有点乱,就可以把匿名方法分离到独立方法中:

 1 List<Student> tt = teacher.Select( 2  3                 GetStudentFromTeacher 4  5                 ).ToList(); 6  7             tt.ForEach(u => 8  9                 {10 11                     if (u != null) Console.WriteLine("姓名:"+u.StuName +"年龄:"+ u.Age);12 13                 });14 15 public static Student GetStudentFromTeacher(Teacher u)16 17         {18 19             Student e = new Student();20 21             if (u.Age < 23)22 23             {24 25                 e.StuName = u.TeachNum;26 27                 e.Age = u.Age;28 29                 e.StuNum =u.TeachNum;30 31             }32 33             else34 35             {36 37                 return null;38 39             }40 41             return e;42 43         }
View Code

希望我的分享给大家带来帮助,也希望大家给出宝贵的意见,小弟也是刚写博客,所以很多地方的不是很专业,大白话为多,希望大家原谅!

原文来自我的个人网站:http://www.yaosutu.cn/archives/568