【Linq】手写Linq To Object
一.数据准备
public class Student { public string Name { get; set; } public int Age { get; set; } } var studentList = new List<Student>(); Student student1 = new Student(); student1.Name = "张三"; student1.Age = 30; Student student2 = new Student(); student2.Name = "李四"; student2.Age = 29; Student student3 = new Student(); student3.Name = "赵春来"; student3.Age = 28; studentList.Add(student1); studentList.Add(student2); studentList.Add(student3);
二.看看Where是什么?
studentList.Where是接受泛型继承IEnumerable类型的数据源,和接受泛型类型返回布尔值的委托,返回IEnumerable类型的扩展方法
三.常规写法
a.foreash 遍历集合得写两遍
b.添加到结果集合得写两遍
不同的是查询条件不同
//查找年龄小于30的学生 { var list = new List<Student>(); foreach (var item in studentList) { if (item.Age < 30) { list.Add(item); } } } //查找姓名大于2个字的学生 { var list = new List<Student>(); foreach (var item in studentList) { if (item.Name.Length > 2) { list.Add(item); } } }
四.第一次封装Linq To Object
a.把集合传递进去
b.把查询条件传递进去--返回布尔值的委托
//1、调用第一次封装Linq to Object CustomerWhereOne(studentList, ((s) => s.Age < 30)); CustomerWhereOne(studentList, new Func<Student, bool>(s => s.Name.Length > 2)); /// <summary> /// 1、第一次封装Linq To Object /// </summary> /// <param name="resource">数据源</param> /// <param name="func">返回布尔值的委托</param> public static List<Student> CustomerWhereOne(List<Student> resource, Func<Student, bool> func) { var result = new List<Student>(); foreach (var item in resource) { if (func(item)) { result.Add(item); } } return result; }
五.第二次封装Linq To Object
a.返回值和数据源改为泛型--List<T>
b.改为扩展方法
//2、调用第二次封装Linq To Object { var resultList = studentList.CustomerWhereTwo((s) => s.Age < 30); var resultList2 = studentList.CustomerWhereTwo(new Func<Student, bool>(s => s.Name.Length > 2)); foreach (var item in resultList) { Console.WriteLine(item.Name); } } /// <summary> /// 2、第二次封装Linq To Object,改为泛型,改为扩展方法 /// </summary> /// <param name="resource">数据源</param> /// <param name="func">返回布尔值的委托</param> public static List<T> CustomerWhereTwo<T>(this List<T> resource, Func<T, bool> func) { var result = new List<T>(); foreach (var item in resource) { if (func(item)) { result.Add(item); } } return result; }
六.第三次封装Linq To Object,改为yield迭代器模式,完成了数据的按需获取,延迟加载
yield和IEnumerable配合使用
a.返回值类型改为IEnumerable
b.return前面加yield
//3、调用第三次封装Linq to Object { var resultList = studentList.CustomerWhereThree((s) => s.Age < 30); var resultList2 = studentList.CustomerWhereThree(new Func<Student, bool>(s => s.Name.Length > 2)); foreach (var item in resultList) { Console.WriteLine(item.Name); } } /// <summary> /// 3、第三次封装Linq To Object,改为迭代器模式,完成了数据的按需获取,延迟加载 /// </summary> /// <param name="resource">数据源</param> /// <param name="func">返回布尔值的委托</param> public static IEnumerable<T> CustomerWhereThree<T>(this IEnumerable<T> resource, Func<T, bool> func) { var result = new List<T>(); foreach (var item in resource) { if (func(item)) { yield return item; } } }
调试代码,我们发现resultList返回的是个ResultView,且提示当展开结果视图枚举IEnumerable
只有当真正使用,去遍历的时候才去调用真正去调用CustomerWhereThree
至此我们通过一步步封装了一个和内置Where一样的CustomerWhereThree方法--Linq To Object
总结
1.Linq是基于委托的封装(例子中的--func),逻辑解耦(查询条件可变化的部分传递进去 --s.Age < 30和s.Name.Length > 2),代码重用(把循环遍历集合和添加到结果集这样的动作封装了起来--foreach (var item in resource))。
2.IEnumerable-yield-利用的迭代器的延迟,按需获取。
旧书不厌百回读,熟读深思子自知。