c# linq查询语句详细使用介绍
本文介绍Linq的使用方法
-
linq介绍
LINQ只不过是实现IEnumerable和IQueryable接口的类的扩展方法的集合。 LINQ可以查询IEnumerable集合或者IQueryable数据源 查询语法 List<string> list = new List<string>() { "a", "b", "cb", "d", "e" }; var result = from s in list where s.Contains("b") select s; 方法语法 方法语法的使用就是调用Enumberable或者Queryable的扩展方法 List<string> list = new List<string>() { "a", "b", "cb", "dc", "e" }; var result = list.Where(s => s.Contains("c")); 上面Where中传递的是一个lambda表达式是匿名函数的简写形式,完整写法如下 var result = list.Where(delegate (string s) { return s.Contains("c"); });
-
标准的查询操作符
** 过滤操作符 > Where操作符 在查询语句中使用where在后面加上过滤条件(函数)就可以了 List<string> list = new List<string>() { "a", "b", "cb", "dc", "ae" }; Func<string, bool> isFilter = s => s.Contains("a"); var result = from s in list where isFilter(s) select s; 在扩展方法中使用where有两个重载 不带索引的重载 List<string> list = new List<string>() { "a", "b", "cb", "dc", "e" }; var result = list.Where(s => s.Contains("c")); 带索引的重载 List<string> list = new List<string>() { "a", "b", "cb", "dc", "e" }; int isum = 0; IEnumerable<string> result = list.Where((s, i) => { if (s.Contains("c")) { isum++; return true; } return false; }).ToList(); // 这里不写ToList()的话linq语句不执行 return Ok(isum); 无论是查询语句还是扩展方法,where都可以使用多个 IEnumerable<string> result = list.Where(s => s.Contains("c")).Where(s => s.Contains("b")); > OfType操作符 使用OfType操作符可以根据数据类型来过滤数据 在查询语句中使用 ArrayList list = new ArrayList() { 2, "a", 5}; var result = from s in list.OfType<int>() select s; // 将ArrayList所有的int类型数据筛选出来 在扩展方法中使用 ArrayList list = new ArrayList() { 2, "a", 5}; var result = list.OfType<string>(); ** 排序操作符 > OrderBy语句 根据指定的字段升序或者降序排序 IList<TestClass> list = new List<TestClass>() { new TestClass() { StudentID = 1, StudentName = "John", Age = 18 } , new TestClass() { StudentID = 2, StudentName = "Steve", Age = 15 } , new TestClass() { StudentID = 3, StudentName = "Bill", Age = 15 } , new TestClass() { StudentID = 4, StudentName = "Ram" , Age = 20 } , new TestClass() { StudentID = 5, StudentName = "Ron" , Age = 19 } }; 在查询语句中使用 var result = from s in list orderby s.Age select s; // 默认是升序排序,ascending可以指定也可以不写 var result = from s in list orderby s.Age descending select s; // 指定descending实现降序 可以指定多条列进行排序 var result = from s in list orderby s.Age, s.StudentID descending select s; 如果s.Age是相同的,那么根据s.StudentID对相同的数据进行排序 在扩展语句中使用 重载一,使用默认规则实现简单的升序排序 var result = list.OrderBy(s => s.Age); // 根据Age字段进行升序排序,不支持降序 重载二,可以传递IComparer泛型实例,实现自定义排序规则 先定义一个实现IComparer的类 public class CompareClass : IComparer<string> { public int Compare(string x, string y) { string str1 = x.Substring(1, 1); string str2 = y.Substring(1, 1); return int.Parse(str1).CompareTo(int.Parse(str2)); // 升序,如果调换str1和str2的位置,可以实现降序 } } 实现排序 IList<TestClass> list = new List<TestClass>() { new TestClass() { StudentID = 1, StudentName = "A3_John", Age = 18 } , new TestClass() { StudentID = 2, StudentName = "A4_Steve", Age = 15 } , new TestClass() { StudentID = 3, StudentName = "A2_Bill", Age = 25 } , new TestClass() { StudentID = 4, StudentName = "A5_Ram" , Age = 20 } , new TestClass() { StudentID = 5, StudentName = "A6_Ron" , Age = 19 } }; var result = list.OrderBy(s => s.StudentName, new CompareClass()); > OrderByDescending语句 根据指定的字段降序排序,只能在扩展方法中使用 var result = list.OrderByDescending(s => s.Age); > ThenBy语句 用于二级排序的升序,只能在扩展方法中使用 var result = list.OrderBy(s => s.Age).ThenBy(s => s.StudentID); 对s.Age排序后的结果中的相同项按照s.StudentID进行升序排序 > ThenByDescending语句 用于二级排序的降序,只能在扩展方法中使用 var result = list.OrderBy(s => s.Age).ThenByDescending(s => s.StudentID); 对s.Age排序后的结果中的相同项按照s.StudentID进行降序排序 > Reverse语句 反序排序,只能用于扩展方法中 var result = list.Reverse(); 对原始集合进行反转排序操作 ** 分组操作符 > GroupBy操作符 GroupBy根据指定的列将相同项分成一组,返回的结果是IEnumerable <IGrouping<TKey, TSource>>类型 每组是IGrouping<TKey, TSource>类型,TKey是键的类型,TSource是结果集合的类型 IList<TestClass> list = new List<TestClass>() { new TestClass() { StudentID = 1, StudentName = "A3_John", Age = 18 } , new TestClass() { StudentID = 2, StudentName = "A4_Steve", Age = 15 } , new TestClass() { StudentID = 3, StudentName = "A2_Bill", Age = 15 } , new TestClass() { StudentID = 4, StudentName = "A5_Ram" , Age = 20 } , new TestClass() { StudentID = 5, StudentName = "A6_Ron" , Age = 20 } }; 在查询语句中使用 var result = from s in list group s by s.Age; foreach(var ageGroup in result) { Trace.WriteLine(ageGroup.Key); // Key是分组的Age值 foreach( TestClass s in ageGroup) { // ... } } 在扩展方法中使用 var result = list.GroupBy(s => s.Age); > ToLookup操作符 只能在扩展方法中使用 var result = list.ToLookup(s => s.Age); ToLookup和GroupBy功能是一样的,但是ToLookup是立即执行的,而GroupBy之后的result是没有值的,只会在使用的时候执行并存储数据 ** 连接操作符 > Join操作符 作用和sql的 inner Join 一样 在扩展方法中使用 例子一: 第一个参数是inner表,第二个参数是outer表的列,第三个参数是inner表的列,第四个参数是结果集的格式 当第二个参数和第三个参数对应的列值相同,那么数据筛选出来,然后经过第四个参数处理后返回 List<string> list1 = new List<string>() { "a", "b", "c", "d", "e" }; List<string> list2 = new List<string>() { "a", "b", "e", "f", "a" }; var result = list1.Join(list2, s1 => s1, s2 => s2, (s1, s2) => s1); 例子二: IList<Demo1> studentList1 = new List<Demo1>() { new Demo1() { StudentID = 1, StudentName = "John", StandardID =1 }, new Demo1() { StudentID = 2, StudentName = "Moin", StandardID =1 }, new Demo1() { StudentID = 3, StudentName = "Bill", StandardID =2 }, new Demo1() { StudentID = 4, StudentName = "Ram" , StandardID =2 }, new Demo1() { StudentID = 5, StudentName = "Ron" } }; IList<Demo2> standardList2 = new List<Demo2>() { new Demo2(){ StandardID = 1, StandardName="Standard 1"}, new Demo2(){ StandardID = 2, StandardName="Standard 2"}, new Demo2(){ StandardID = 3, StandardName="Standard 3"} }; var result = studentList1.Join(standardList2, s1 => s1.StandardID, s2 => s2.StandardID, (s1, s2) => { return new { StudentName = s1.StudentName, StandardName = s2.StandardName }; }); 在查询语句中使用 使用上面的studentList1和standardList2为例 var result = from s1 in studentList1 join s2 in standardList2 on s1.StandardID equals s2.StandardID select new { StudentName = s1.StudentName, standardName = s2.StandardName }; > GroupJoin操作符 作用和sql的 left join,right join类似 在扩展方法中使用 还是使用上面的studentList1和standardList2为例 var result = studentList1.GroupJoin(standardList2, s1 => s1.StandardID, s2 => s2.StandardID, (s1, s2Obj) => { return new { studentName = s1.StudentName, standardName = s2Obj // s2Obj自动将 s2 转成 IEnumerable类型 }; }); 在查询语句中使用 var result = from s1 in studentList1 join s2 in standardList2 on s1.StandardID equals s2.StandardID into s3 select new { standard = s3, studentName = s1.StudentName }; ** 投影操作符 > select操作符 和sql中的select类似 在查询语句中使用 var result = from item in someList select item; var result = from item in someList select new { column1 = item.Name, column2 = item.Age }; 在扩展方法中使用 在扩展方法中Select方法仅仅用来格式化数据,在查询数据时是可选项 var result = list.Select(s => new { Name = s.StudentName, Age = s.Age }); > SelectMany方法 SelectMany方法只能在扩展方法中使用 SelectMany的作用是将指定列对应的IEnumerable列值合并成一个集合,用法如下 定义两个类 public class Students { public string Name { get; set; } public int Age { get; set; } } public class ClassNames { public IEnumerable<Students> students { get; set; } public string Name { get; set; } } 使用SelectMany List<ClassNames> selectManyTest = new List<ClassNames>() { }; selectManyTest.Add(new ClassNames() { students = new List<Students>() { new Students() { Name = "小张", Age = 11 } }, Name = "班级一" }); selectManyTest.Add(new ClassNames() { students = new List<Students>() { new Students() { Name = "小王", Age = 21 } }, Name = "班级二" }); selectManyTest.Add(new ClassNames() { students = new List<Students>() { new Students() { Name = "小红", Age = 22 } }, Name = "班级三" }); var result = selectManyTest.SelectMany(s => s.students); result的结果 [{"Name":"小张","Age":11},{"Name":"小王","Age":21},{"Name":"小红","Age":22}] 这种用法其实和Select的作用是一致的 var result = selectManyTest.Select(s => s.students); 关键是下面的这种用法 var result = selectManyTest.SelectMany(s => s.students, (s1, s2) => { return new { 班级名称 = s1.Name, 学生姓名 = s2.Name, 学生年龄 = s2.Age }; }); 结果是 [{"班级名称":"班级一","学生姓名":"小张","学生年龄":11},{"班级名称":"班级二","学生姓名":"小王","学生年龄":21},{"班级名称":"班级三","学生姓名":"小红","学生年龄":22}] 从这里可以看出SelectMany的优势是将嵌套的复杂类型综合到一个集合中 ** 量词操作符 IList<TestClass> studentList = new List<TestClass>() { new TestClass() { StudentID = 1, StudentName = "John", Age = 18 } , new TestClass() { StudentID = 2, StudentName = "Steve", Age = 15 } , new TestClass() { StudentID = 3, StudentName = "Bill", Age = 25 } , new TestClass() { StudentID = 4, StudentName = "Ram" , Age = 20 } , new TestClass() { StudentID = 5, StudentName = "Ron" , Age = 19 } }; > ALL操作符 指定筛选条件如果元素全部满足则返回true bool result = studentList.All(s => s.Age > 18 && s.Age < 20); // false > Any操作符 指定筛选条件只要有一个满足就返回true bool result = studentList.Any(s => s.Age > 18 && s.Age < 20); // true > Contains操作符 值类型用法 List<int> list = new List<int>() { 1, 2, 3, 4, 5 }; bool result = list.Contains(4); 引用类型用法 引用类型默认比较的是引用,如果要实现自定义比较引用类型,就要实现一个IEqualityComparer类 创建一个IEqualityComparer类 public class StudentComparer : IEqualityComparer<TestClass> { public bool Equals(TestClass x, TestClass y) { if (x.StudentID == y.StudentID && x.StudentName.ToLower() == y.StudentName.ToLower() && x.Age == y.Age) { return true; } return false; } public int GetHashCode(TestClass obj) { Trace.WriteLine(obj.GetHashCode()); return obj.GetHashCode(); } } 使用 bool result = studentList.Contains(new TestClass() { StudentID = 2, StudentName = "Steve", Age = 15 }, new StudentComparer()); // true ** 聚合操作符 在linq中聚合函数不能直接使用在查询语句中,但是可以像下面这种方式使用 var result = (from s in studentList where s.Age > 20 select s).Average(s => s.Age); > Aggregate操作符 用来累积结果 重载一 List<string> list = new List<string> { "a", "b", "c", "d" }; var result = list.Aggregate((s1, s2) => { return s1 + s2; }); // "abcd" 重载二,需要一个seed作为初始值 List<string> list = new List<string> { "a", "b", "c", "d" }; var result = list.Aggregate("结果是:", (s1, s2) => { return s1 + s2; }); // "结果是:abcd" 重载三,需要一个Func代理函数用来对计算的结果做处理 List<string> list = new List<string> { "a", "b", "c", "d" }; var result = list.Aggregate(String.Empty, (s1, s2) => { return s1 += s2 + ","; }, res => res.Substring(0, res.Length - 1)); // "a,b,c,d" > Average操作符 用来计算集合中的数字值的平均值 计算由数字组成的集合的平均值 List<int> list = new List<int>() { 1, 2, 3, 4, 5 }; var result = list.Average(); 传递lambda表达式,用来计算引用类型中的数字的平均值 var result = studentList.Average(s => s.Age); > Count操作符 返回集合的元素的个数 var result = studentList.Count(); 返回满足给定条件的元素个数 var result = studentList.Count(s => s.Age > 19); > Max操作符 返回数字集合的最大值 List<int> list = new List<int>() { 1, 2, 3, 7, 4, 5, 6 }; var result = list.Max(); // 最大值 7 var result = list.Max(s => s * 2); // 将元素乘2后计算最大值,14 返回引用类型集合数字属性的最大值 var result = studentList.Max(s => s.Age); 对于引用类型可以实现自定义的Max比较 先声明一个类,实现了 IComparable 接口 public class TestClass: IComparable<TestClass> { public int StudentID { get; set; } public string StudentName { get; set; } public int Age { get; set; } public int CompareTo(TestClass other) // 用来筛选出StudentName长度最长的一项 { if(this.StudentName.Length >= other.StudentName.Length) { return 1; } return 0; } } 使用 IList<TestClass> studentList = new List<TestClass>() { new TestClass() { StudentID = 1, StudentName = "John", Age = 18 } , new TestClass() { StudentID = 2, StudentName = "Steve", Age = 15 } , new TestClass() { StudentID = 3, StudentName = "Bill", Age = 25 } , new TestClass() { StudentID = 4, StudentName = "Ram" , Age = 20 } , new TestClass() { StudentID = 5, StudentName = "Ron" , Age = 19 } }; var result = studentList.Max(); // 直接调用Max即可 Min的使用方式和Max是一直的,不再赘述 > Sum操作符 返回数字集合的总和 List<int> list = new List<int>() { 1, 2, 3, 7, 4, 5, 6 }; var result = list.Sum(); // 返回总和 var result = list.Sum(s => s * 2 + 1); // 返回每一项乘2加1后的总和 返回应用类型集合数字属性的总和 var result = studentList.Sum(s => s.Age); // 计算年龄的总和 var result = studentList.Sum(s => { if(s.Age > 18) { return 1; } return 0; }); // 计算年龄大于18的人数 ** 元素操作符 List<int> intList = new List<int>() { 10, 21, 30, 45, 50, 87 }; > ElementAt操作符 根据索引找出元素,超出范围会报错 var result = intList.ElementAt(1); > ElementAtOrDefault操作符 根据索引找出元素,超出范围返回默认值,整数默认值是0,字符串默认值是null var result = intList.ElementAtOrDefault(9); > First操作符 返回第一个元素或者第一个满足条件的元素,如果给定的集合是空的,或者没有一个元素满足条件,那么会报错 var result = intList.First(); // 返回集合中的第一个元素 var result = intList.First(s => s > 30); // 返回满足条件的第一个元素 Last的用法和First一致 > FirstOrDefault操作符 返回第一个元素或者第一个满足条件的元素,如果给定的集合是空的,或者没有一个元素满足条件那么返回默认值 用法和上面一样 LastOrDefault的用法和FirstOrDefault一致 > Single操作符 返回集合中的唯一一个元素,或者指定条件后唯一一个元素,如果没有元素或者多于一个元素那么报错 List<int> intList = new List<int>() { 10 }; var result = intList.Single(); > SingleOrDefault操作符 作用和Single类似,如果没有找到元素,那么返回默认值,然而,如果有多个元素那么同样报错 List<int> intList = new List<int>() { 10,20 }; var result = intList.SingleOrDefault(s => s > 10); ** 相等运算符 > SequenceEqual 用于比较两个集合中的元素是否相等,如果元素是值类型,那么比较元素的值和顺序,如果是引用类型那么比较值的引用 值类型比较 List<int> intList1 = new List<int>() { 10,20 }; List<int> intList2 = new List<int>() { 10, 20 }; var result = intList1.SequenceEqual(intList2); // true 引用类型比较 List<TestClass> TestList1 = new List<TestClass>() { new TestClass() { StudentID = 1, StudentName = "John", Age = 18 } }; List<TestClass> TestList2 = new List<TestClass>() { new TestClass() { StudentID = 1, StudentName = "John", Age = 18 } }; var result = TestList1.SequenceEqual(TestList2); // false 自定义引用类型比较 如果不想比较引用类型的时候比较引用地址,那么可以使用自定义比较 首先,创建一个实现了IEqualityComparer接口的类 private class SequenceEqualComparer : IEqualityComparer<TestClass> { public bool Equals(TestClass x, TestClass y) { if(x.StudentID == y.StudentID && x.StudentName == y.StudentName && x.Age == y.Age) { return true; } return false; } public int GetHashCode(TestClass obj) { return obj.GetHashCode(); } } 使用 List<TestClass> TestList1 = new List<TestClass>() { new TestClass() { StudentID = 1, StudentName = "John", Age = 18 } }; List<TestClass> TestList2 = new List<TestClass>() { new TestClass() { StudentID = 1, StudentName = "John", Age = 18 } }; var result = TestList1.SequenceEqual(TestList2, new SequenceEqualComparer()); // true ** 串联运算符 > Concat运算符 用于连接两个集合 var result = TestList1.Concat(TestList2); ** 生成运算符 > DefaultIfEmpty操作符 如果调用此方法的集合是空的则返回一个新的集合,新集合包含一个默认值元素 不指定默认值 List<string> list = new List<string>(); var result = list.DefaultIfEmpty(); // 结果 [null] 指定默认值 var result = list.DefaultIfEmpty("haha"); // 结果 ["haha"] 本质 DefaultIfEmpty本质作用是将一个集合拷贝了一份,如果集合是空的自动填充一个默认值 List<string> list = new List<string>() { "a" }; var temp = list.DefaultIfEmpty("haha"); var result = temp == list; // false > Empty, Range, Repeat 操作符 这三个运算符不是IEnumerable 和 IQueryable的扩展方法,而是Enumerable的静态方法 Empty操作符 返回一个空的集合 var result = (Enumerable.Empty<string>()).GetType().Name; // "String[]" Range操作符 返回一个集合,元素从指定的数字开始,按照指定的个数依次递增 var result = Enumerable.Range(10, 10); // [10,11,12,13,14,15,16,17,18,19] Repeat操作符 返回一个集合,元素是指定个数的相同的指定元素 var result = Enumerable.Repeat<string>("a", 10); // ["a","a","a","a","a","a","a","a","a","a"] ** 集操作符 > Distinct 取出集合中重复项,并返回一个新的集合 对值类型集合的操作 List<string> list = new List<string>() { "a", "b", "c", "d", "b", "c" }; var result = list.Distinct(); // ["a","b","c","d"] 对引用类型集合的操作,默认无效,需要自己实现IEqualityComparer类 首先实现IEqualityComparer类 Equals,GetHashCode方法会自动调用,当GetHashCode返回的整数(引用)不一致,那么会执行Equals方法 private class DistinctComparer : IEqualityComparer<TestClass> { public bool Equals(TestClass x, TestClass y) { if(x.StudentID == y.StudentID && x.StudentName == y.StudentName && x.Age == y.Age) { return true; } return false; } public int GetHashCode(TestClass obj) { return obj.StudentID.GetHashCode(); // 注意,表示如果 StudentID的GetHashCode 相同,那么过滤掉这个数据 } } 使用 List<TestClass> studentList = new List<TestClass>() { new TestClass() { StudentID = 1, StudentName = "John", Age = 18 } , new TestClass() { StudentID = 1, StudentName = "John", Age = 18 } , new TestClass() { StudentID = 2, StudentName = "Steve", Age = 15 } }; var result = studentList.Distinct(new DistinctComparer()); > Except 返回一个新的集合,集合的成员是list1在list2中不存在的元素 对值类型集合的操作 List<string> list1 = new List<string>() { "a", "b", "c" }; List<string> list2 = new List<string>() { "c", "d", "a" }; var result = list1.Except(list2); // ["b"] 对引用类型集合的操作,同样也要自己实现IEqualityComparer类 创建一个IEqualityComparer类,和上面一模一样 private class ExceptComparer : IEqualityComparer<TestClass> { public bool Equals(TestClass x, TestClass y) { if (x.StudentID == y.StudentID && x.StudentName == y.StudentName && x.Age == y.Age) { return true; } return false; } public int GetHashCode(TestClass obj) { return obj.StudentID.GetHashCode(); // 注意,表示如果 StudentID的GetHashCode 相同,那么过滤掉这个数据 } } 使用 List<TestClass> studentList1 = new List<TestClass>() { new TestClass() { StudentID = 1, StudentName = "John", Age = 18 } , new TestClass() { StudentID = 1, StudentName = "John", Age = 18 } , new TestClass() { StudentID = 2, StudentName = "Steve", Age = 15 } }; List<TestClass> studentList2 = new List<TestClass>() { new TestClass() { StudentID = 1, StudentName = "John", Age = 18 } , new TestClass() { StudentID = 3, StudentName = "John", Age = 18 } , new TestClass() { StudentID = 4, StudentName = "Steve", Age = 15 } }; var result = studentList1.Except(studentList2, new ExceptComparer()); // [{"StudentID":2,"StudentName":"Steve","Age":15}] > Intersect 相当于取交集 值类型集合操作 List<string> list1 = new List<string>() { "a", "b", "c" }; List<string> list2 = new List<string>() { "c", "d", "a" }; var result = list1.Intersect(list2); // ["a","c"] 引用类型集合操作,同样也是要创建IEqualityComparer类,实现和上面是一模一样,不再赘述 使用 var result = studentList1.Intersect(studentList2, new IntersectComparer()); // 返回结果 [{"StudentID":1,"StudentName":"John","Age":18}] > Union 将两个集合拼接起来,并且剔除掉重复项 值类型集合操作 List<string> list1 = new List<string>() { "a", "b", "c", "a", "b" }; List<string> list2 = new List<string>() { "c", "d", "a" }; var result = list1.Union(list2); // ["a","b","c","d"] 引用类型集合操作,同样也是要创建IEqualityComparer类,实现和上面是一模一样,不再赘述 使用 var result = studentList1.Union(studentList2, new UnionComparer()); 返回结果如下 /* [ {"StudentID":1,"StudentName":"John","Age":18}, {"StudentID":2,"StudentName":"Steve","Age":15}, {"StudentID":3,"StudentName":"John","Age":18}, {"StudentID":4,"StudentName":"Steve","Age":15} ] */ ** 分区操作符 > Skip操作符 过滤掉集合中指定个数的元素,返回剩余元素组成的集合 List<string> list = new List<string>() { "a", "b", "c" }; var result = list.Skip(2); // ["c"] > SkipWhile操作符 指定条件过滤,如果条件满足全部过滤掉,直到条件为false,返回剩余元素组成的集合 List<int> list = new List<int>() { 1, 2, 5, 2, 4, 5, 6 }; var result = list.SkipWhile((s, i) => s < 3); // [5,2,4,5,6] > Take操作符 功能和Skip相反,获取指定数量的元素,并返回新的集合 List<string> list = new List<string>() { "a", "b", "c" }; var result = list.Take(2); // ["a","b"] > TakeWhile操作符 功能和SkipWhile相反,获取满足指定条件的元素,直到条件不满足,返回新的集合 List<int> list = new List<int>() { 1, 2, 5, 2, 4, 5, 6 }; var result = list.TakeWhile((s, i) => s < 3); // [1,2] ** 转换运算符 > AsEnumerable操作符 将集合强制转换成IEnumerable集合 int[] arr = new int[] { 1, 2, 3, 4, 5 }; var result = arr.AsEnumerable(); > AsQueryable操作符 将集合强制转换成IQueryable集合 List<int> list = new List<int>() { 1, 2, 5, 2, 4, 5, 6 }; var result = list.AsQueryable(); > Cast操作符 作用和AsEnumerable是一样的 int[] arr = new int[] { 1, 2, 3, 4, 5 }; var result = arr.Cast<int>(); 等效于 var result = (IEnumerable<int>)arr; > ToArray,ToList,ToDictionary扩展方法 To系列的操作,会强制让sql语句执行结果并且将数据缓存在本地 int[] arr = new int[] { 1, 2, 3, 4, 5 }; ToArray使用 int[] result = arr.ToArray<int>(); ToList使用 List<int> result = arr.ToList<int>(); ToDictionary使用 var result = arr.ToDictionary<int, int>(s => s);
-
Linq中的Expression类型
由Func和Action类型的委托构建的lambada表达式在编译期间会转换成可执行的代码,linq引入新的Expression类型,将lambda表达式转换成Expression树而不是可执行代码 传统写代理的方式 Func<int, bool> isTest = s => s > 5; Expression写代理的方式 Expression<Func<int, bool>> isTest = s => s > 5; 调用Expression代理 调用之前需要先编译一下 Func<int, bool> isIWant = isTest.Compile(); bool result = isIWant(3); 为什么要有表达式树? 编译的区别 Func编译后的代码 {Method = {Boolean <.ctor>b__9_0(Int32)}} Expression编译后的代码 {s => (s > 5)} 很明显的感觉到,Func编译后被改了,表达式树更加的透明,你可以轻松的调用Expression的方法访问方法的每一个部分 处理代码的区别 Func值适合当前程序集中运行,也就是说只适合内存中的集合,因为如果涉及数据库查询的话,数据库无法获知编译后的IL代码到底是个啥 Expression表达式树,专门用来处理类似数据库的操作 执行效率 Func要想操作数据库,需要借助Entity Frameworks将可执行代码编译成Sql查询字符串发送到sql server数据库中 使用Expression表达式树,可以轻松的将lambda表达式转换成Sql语句,因为Expression内置了很多属性和方法方便获取表达式的每一部分,所以执行效率更快 总之,一句话,操作数据库使用Expression更好
-
延迟执行linq查询
linq表达式不会立即执行,而是用到了才会调用,从而保证每次使用linq时都是最新的数据 默认情况下linq的延迟加载不会有什么特殊的效果,只是简单的延迟而已,但是你可以自定义扩展方法使用yield关键字实现自己的延迟效果 首先,要定义扩展方法,需要一个顶级静态类 public static class EnumerableExtensionMethodsDemo { public static IEnumerable<int> GetIWant(this List<int> test) { foreach (int item in test) { if(item > 5 && item < 10) { yield return item; } } } } 使用 List<int> list = new List<int>() { 1, 2, 10, 50, 30, 5, 7, 9, 11 }; var result = from s in list.GetIWant() select s; foreach (int i in result) { // 在这里才会调用result查询语句 }
-
立即执行linq查询
上面讲到的以to开头的扩展方法,都可以让linq语句立即执行
-
linq中使用let关键字
List<string> list = new List<string>() { "sa", "rb", "bc", "sd" }; var result = from s in list where s.ToLower().StartsWith("s") select s.ToLower(); 上面这个查询语句中 ToLower 使用了两次,很啰嗦,可以使用let简化 var result = from s in list let lowerItem = s.ToLower() where lowerItem.StartsWith("s") select lowerItem;
-
into关键字
into关键字单独使用的作用,是将上个查询语句的结果传递到下一个查询语句中,两个查询语句中的变量互不影响 List<string> list = new List<string>() { "sa", "rb", "bc", "sd" }; var result = from s in list where s.ToLower().StartsWith("s") select s into s where s.ToLower().EndsWith("a") select s; // ["sa"]