首页 > 代码库 > 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:

  1. They are more concise and readable, especially when filtering multiple conditions.

  2. They provide powerful filtering, ordering, and grouping capabilities with a minimum of application code.

  3. 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