首页 > 代码库 > Linq学习随笔一------LINQ to Objects
Linq学习随笔一------LINQ to Objects
Linq是Language Integrated Query的简称,它是C# 3.0中新添加的,包含在微软.net framework 3.5,用以简化查询查询操作。它主要包含了3块,Linq to Object、Linq to SQL、Linq to XML,其中Linq to Object和对于对象的查询,Linq to XML则又提供了对XML格式数据的检索、设置等功能,Linq to SQL顾名思义就是针对SQL的功能。
一.LINQ to Objects
The term "LINQ to Objects" refers to the use of LINQ queries with any IEnumerable or IEnumerable<T> collection directly, without the use of an intermediate LINQ provider or API such as LINQ to SQL or LINQ to XML. You can use LINQ to query any enumerable collections such as List<T>, Array, or Dictionary<TKey,TValue>. The collection may be user-defined or may be returned by a .NET Framework API.
In a basic sense, LINQ to Objects represents a new approach to collections. In the old way, you had to write complex
foreach
loops that specified how to retrieve data from a collection. In the LINQ approach, you write declarative code that describes what you want to retrieve.In addition, LINQ queries offer three main advantages over traditional
foreach
loops:
They are more concise and readable, especially when filtering multiple conditions.
They provide powerful filtering, ordering, and grouping capabilities with a minimum of application code.
They can be ported to other data sources with little or no modification.
In general, the more complex the operation you want to perform on the data, the more benefit you will realize by using LINQ instead of traditional iteration techniques.
上面引用微软donet官网中对LINQ to Objects的简单描述,可以把LINQ看做简化foreach对object操作的替换方案,至于效率上与foreach是否有差异,因为因人而异使用两种方式写出来的代码也不同,所以不好做比较,这里不做讨论。LINQ有两种调用方法,一种是表达式语法,一种是方法调用语法,以下示例代码中用到的集合和集合中对象对应的类如下:
1 public class Hero 2 { 3 public string Name; 4 public string Class; 5 public string Weapon; 6 7 public Hero(string name, string c, string weapon) 8 { 9 Name = name; 10 Class = c; 11 Weapon = weapon; 12 } 13 }
1 List<string> baseObjList = new List<string>() { "a", "b", "bb", "c", "dd", "ddd", "a" }; 2 List<string> baseObjList2 = new List<string>() { "a", "b", "bb", "c", "dd", "dddd" }; 3 List<Hero> customObjList = new List<Hero> { new Hero("Bei Liu", "WuZhe", "Jian"), new Hero("Fei Zhang", "WuZhe", "Mao"), new Hero("Yu Guan", "WuZhe", "DaDao"), new Hero("Geliang Zhu", "MouShi", "ShanZi") }; 4 List<Hero> customObjList2 = new List<Hero> { new Hero("Bei Liu", "WuZhe", "ShuangJian"), new Hero("Fei Zhang", "WuZhe", "Mao"), new Hero("Yun Zhao", "WuZhe", "Qiang"), new Hero("Geliang Zhu", "MouShi", "ShanZi") }; 5 ArrayList customObjList3 = new ArrayList() { new Hero("Bei Liu", "WuZhe", "ShuangJian"), new Hero("Fei Zhang", "WuZhe", "Mao"), new Hero("Yun Zhao", "WuZhe", "Qiang"), new Hero("Tong Pang", "MouShi", "Zhang") };
具体调用代码如下:
1 // Using query expression syntax. 2 #region expression 1 3 var baseResult = from b in baseObjList 4 where b.Substring(0, 1) == "b" || b.Substring(0, 1) == "d" 5 orderby b.Length, b.Substring(0, 1) descending 6 select b; 7 #endregion 8 #region expression 2 9 var baseResult2 = from a in baseObjList 10 from b in baseObjList2 11 select new 12 { 13 PartA = a, 14 PartB = b 15 }; 16 #endregion 17 // Using method-based query syntax. 18 var baseResult3 = baseObjList.Where(b => b.Substring(0, 1) == "b" || b.Substring(0, 1) == "d").OrderBy(b => b.Length).ThenByDescending(b => b.Substring(0, 1)); //The function is same as expression 1 19 var baseResult4 = baseObjList.SelectMany(a => baseObjList2.Select( //The function is same as expression 2 20 b => new 21 { 22 PartA = a, 23 PartB = b 24 })); 25 var baseResult5 = baseObjList.Except(baseObjList2); 26 var baseResult6 = baseObjList.Concat(baseObjList2).OrderBy(s => s); 27 var baseResult7 = baseObjList.Union(baseObjList2); 28 var baseResult8 = baseObjList.Intersect(baseObjList2); 29 var baseResult9 = baseObjList.SomeWordCount("a"); 30 31 // Using query expression syntax. 32 #region expression 3 33 var customResult = from c in customObjList 34 let cl = c.Class 35 let name = c.Name 36 let weapon = c.Weapon 37 where cl == "WuZhe" 38 select new 39 { 40 n = name, 41 w = weapon 42 }; 43 #endregion 44 #region expression 4 45 var customResult2 = from c in customObjList 46 group c by c.Class into classGroup 47 where classGroup.Key == "WuZhe" 48 select (from g in classGroup 49 where g.Name == "Yu Guan" 50 select g); 51 #endregion 52 #region expression 5 53 var customResult3 = from c in customObjList 54 join d in customObjList2 55 on c.Name equals d.Name 56 select d; 57 #endregion 58 #region expression 6 59 var customResult4 = from Hero c in customObjList3 60 where c.Class == "WuZhe" 61 select c; 62 #endregion 63 // Using method-based query syntax. 64 var customResult5 = customObjList.Where(c => c.Class == "WuZhe").Select(r => new { n = r.Name, w = r.Weapon }); //The function is same as expression 3 65 var customResult6 = customObjList.GroupBy(c => c.Class).Where(c => c.Key == "WuZhe").Single().Where(c => c.Name == "Yu Guan"); //The function is same as expression 4 66 var customResult7 = customObjList.Join(customObjList2, a => a.Name, b => b.Name, (a, b) => a); //The function is same as expression 5 67 var customResult8 = customObjList.Except(customObjList2, new HeroUnitComparer()); 68 var customResult9 = customObjList.Concat(customObjList2).OrderBy(c => c.Name); 69 var customResult10 = customObjList.Union(customObjList2, new HeroUnitComparer()); 70 var customResult11 = customObjList.Intersect(customObjList2, new HeroUnitComparer());
- let
使用let 建立范围变量,这个范围变量在后续的where子句中使用,如上面代码第34行所示
- join
连接两个集合,与SQL语句中的join功能类似,如上面代码#region expression 5内和66行所示
- Except
比较两个字符串集合,查找出两个集合中的差集,方法左边的集合里在方法右边集合中不存在的字符串集合,该方法只包含在方法调用语法里,如上面代码第25,67行所示,25行中调用的方法是public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second),67行中调用的方法是public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer),两个方法的差别在第三个参数IEqualityComparer<TSource> comparer,如果集合中是自定义类对象,这时候就需要使用到第三个参数,否则将默认使用默认的对象比较方法,此时Except将得不到我们的期待结果。自定义comparer类的示例代码如下
1 internal class HeroUnitComparer : IEqualityComparer<Hero> 2 { 3 public bool Equals(Hero a, Hero b) 4 { 5 if (Object.ReferenceEquals(a, b)) 6 { 7 return true; 8 } 9 if (Object.ReferenceEquals(a, null) 10 || Object.ReferenceEquals(b, null)) 11 { 12 return false; 13 } 14 return a.Name.Equals(b.Name, StringComparison.OrdinalIgnoreCase) 15 && a.Class.Equals(b.Class, StringComparison.OrdinalIgnoreCase) 16 && a.Weapon.Equals(b.Weapon, StringComparison.OrdinalIgnoreCase); 17 } 18 19 public int GetHashCode(Hero h) 20 { 21 int hashName = h.Name == null ? 0 : h.Name.GetHashCode(); 22 int hashClass = h.Class == null ? 0 : h.Class.GetHashCode(); 23 int hashWeapon = h.Weapon == null ? 0 : h.Weapon.GetHashCode(); 24 return hashName ^ hashClass ^ hashWeapon; 25 } 26 }
HeroUnitComparer类继承接口IEqualityComparer<T>,类中需要实现两个方法bool Equals(T x, T y),int GetHashCode(T obj)
- Concat
合并两个集合,但是不去重,调用方法如上面代码第26,68行所示,与Except方法一样,有两种重载方法
- Union
合并两个集合,并且去重,调用方法如上面代码第27,69行所示,与Except方法一样,有两种重载方法
- Intersect
返回两个集合的交集,调用方法如上面代码第70行所示,与Except方法一样,有两种重载方法
- 为 LINQ 查询添加自定义方法
定义一个static class,并且class中包含一个static方法,方法的第一个参数必须是this为前缀,第一个参数的类型既是该方法作用的类型,调用方法和LINQ自带的方法没有区别。
1 public static class LinqExtension 2 { 3 public static int SomeWordCount(this IEnumerable<string> col, string word) 4 { 5 return (from c in col 6 where c == word 7 select c).Count(); 8 } 9 }
上面并没有介绍所有的Linq中的方法,只是一些功能比较特殊的做了简单介绍,示例代码中还有部分基本的Linq使用方法没有介绍,要想完全搞懂这些示例代码,还需要自己具体跑一下,看下输出结果这样更容易理解。
本文参考 https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/linq/linq-to-objects
Linq学习随笔一------LINQ to Objects