1、數據準備
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);
2、看看Where是什麼?
studentList.Where是接受泛型繼承IEnumerable類型的數據源,和接受泛型類型返回布爾值的委託,返回IEnumerable類型的擴展方法
3、原始寫法
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); } } }
4、第一次封裝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; }
5、第二次封裝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; }
6、第三次封裝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--利用的迭代器的延遲,按需獲取。