背景
传统上,针对数据的查询都以简单的字符串表示,而没有编译时类型检查或 IntelliSense 支持。此外,还需要针对每种数据源学习一种不同的查询语言:SQL 数据库、XML 文档、各种 Web 服务等等。 LINQ 使查询成为 C# 中的一流语言构造。 可以使用语言关键字和熟悉的运算符针对强类型化对象集合编写查询。
注意事项
版本需求:.NET Framework 3.5 或更高版本
查询对象:SQL Server 数据库、XML 文档、ADO.NET 数据集以及支持 IEnumerable 或泛型 IEnumerable<T> 接口的任何对象集合
引用包:System.Linq
以下按照使用度排序介绍。
Where
用于过滤数据,减少IF分支语句。
例子:
StringBuilder str = new StringBuilder(); foreach (int item in list.Where(d => d % 2 == 0)) { str.Append(item); }
老式IF用法:
StringBuilder str = new StringBuilder(); foreach (int item in list) { if (item % 2 == 0) { str.Append(item); } }
Take
从数据源开始位置读取指定的元素个数用。
例子:
var list = Enumerable.Range(1, 100000); foreach (int item in list.Take(10)) { Console.WriteLine(item.ToString()); }
Select
抽取数据源中类型的指定元素组建成新的类型。主要用于简化数据列或者转换数据类型,以及获取元素Index。
例子:
var list = new List<Animal> { new Animal{ Name="hot dog",Sex=1,Age=10}, new Animal{ Name="big dog",Sex=0,Age=11}, new Animal{ Name="bin dog",Sex=0,Age=12}, new Animal{ Name="baby dog",Sex=1,Age=13}, }; foreach (string item in list.Select(a => a.Name)) { Console.WriteLine(item.ToString()); } foreach (var item in list.Select(a => new { Name = a.Name, Length = a.Age * 2, Type = "S" })) { Console.WriteLine(item.ToString()); } foreach (var item in list.Select((value, index) => new { Number = index, Name = value })) { Console.WriteLine(item.ToString()); } foreach (string item in list.Select(a => a.Sex.ToString("D2"))) { Console.WriteLine(item.ToString()); } foreach (int item in list.Select(a => a.Age * 2)) { Console.WriteLine(item.ToString()); }
结果:
SelectMany
将数据源降维抽取,减少For循环。类似Select,适合多重子集的数据源抽取数据。
例子:
var parameters = new Parameter[] { new Parameter() { Name = "正一", Numbers = new int[] { 1, 2, 3 } }, new Parameter() { Name = "清次", Numbers = new int[] { 1, 3, 5 } }, new Parameter() { Name = "誠三", Numbers = new int[] { 2, 4, 6 } }, new Parameter() { Name = "征史", Numbers = new int[] { 9, 8, 7 } }, }; StringBuilder str = new StringBuilder(); var result = parameters.SelectMany(value => value.Numbers); foreach (int value in result) { str.Append($"{value},"); } Console.WriteLine(str.ToString());
结果:
如果使用Select就是如下写法:
var parameters = new Parameter[] { new Parameter() { Name = "正一", Numbers = new int[] { 1, 2, 3 } }, new Parameter() { Name = "清次", Numbers = new int[] { 1, 3, 5 } }, new Parameter() { Name = "誠三", Numbers = new int[] { 2, 4, 6 } }, new Parameter() { Name = "征史", Numbers = new int[] { 9, 8, 7 } }, }; var results = parameters.Select(value => value.Numbers); StringBuilder str = new StringBuilder(); foreach (int[] values in results) { foreach (int number in values) { str.Append($"{number},"); } } Console.WriteLine(str.ToString());
结果:
Distinct
去掉重复数据留下一个,一般用于基础数据类型。如果是类需要指定比较方法。
int[] dataA = new int[] { 0, 1, 3, 3, 2 }; List<float> dataB = new List<float>() { 1.5f, 1.5f, 1.5f, 1.5f }; IEnumerable<int> dataA_D = dataA.Distinct(); IEnumerable<float> dataB_D = dataB.Distinct(); foreach (var d in dataA_D) { Console.WriteLine(d); } foreach (var d in dataB_D) { Console.WriteLine(d); }
Any
用来判断列表是否为空,速度比Count()快。如果是类,可以指定判断条件。
int[] numbersA = new int[] { }; int[] numbersB = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; var list = new List<Animal> { new Animal{ Name="hot dog",Sex=1}, new Animal{ Name=null,Sex=0}, new Animal{ Name="bin dog",Sex=0}, new Animal{ Name="baby dog",Sex=1}, }; Console.WriteLine(numbersA.Any()); Console.WriteLine(numbersB.Any()); Console.WriteLine(list.Any(a => a.Name == null));
Join
两组数据结合。也可以用来根据某个表排序数据。
public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>( this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector );
参数说明:
outer:结合的数据列表A
inner:结合的数据列表B
outerKeySelector:列表A的主键字段
innerKeySelector:列表B的主键字段
resultSelector:返回结果定义。(匿名类居多)
PersonData[] persons = new PersonData[] { new PersonData() { Name = "正一郎", ItemID = 0 }, new PersonData() { Name = "清次郎", ItemID = 1 }, new PersonData() { Name = "誠三郎", ItemID = 2 }, new PersonData() { Name = "征史郎", ItemID = 0 }, }; ItemData[] items = new ItemData[] { new ItemData() { ID = 0, Name = "金" }, new ItemData() { ID = 1, Name = "権力" }, }; var joinList = persons.Join( items, person => person.ItemID, item => item.ID, (person, item) => new { PersonName = person.Name, ItemName = item.Name }); foreach (var item in joinList) { Console.WriteLine($"Person:{item.PersonName}, Item:{item.ItemName}"); }
Except
求两个数据列表的差分集合用。
int[] numbersA = new int[] { 1, 2, 3, 4, 5 }; int[] numbersB = new int[] { 8, 6, 4, 2, 0 }; IEnumerable<int> results = numbersA.Except(numbersB); foreach (var d in results) { Console.WriteLine(d); }
自定义比较条件的情况
class Parameter { public int ID { get; set; } public string Name { get; set; } public override string ToString() { return string.Format("ID:{0}, Name:{1}", ID, Name); } } class ParameterComparer : IEqualityComparer<Parameter> { public bool Equals(Parameter i_lhs, Parameter i_rhs) { if (i_lhs.ID == i_rhs.ID && i_lhs.Name == i_rhs.Name) { return true; } return false; } public int GetHashCode(Parameter i_obj) { return i_obj.ID ^ i_obj.Name.GetHashCode(); } } class Program { static void Main(string[] args) { Parameter[] dataA = new Parameter[] { new Parameter() { ID = 0, Name = "正一郎" }, new Parameter() { ID = 5, Name = "清次郎" }, new Parameter() { ID = 3, Name = "誠三郎" }, new Parameter() { ID = 9, Name = "征史郎" }, }; Parameter[] dataB = new Parameter[] { new Parameter() { ID = 5, Name = "清次郎" }, new Parameter() { ID = 3, Name = "誠三郎" }, new Parameter() { ID = 2, Name = "征史郎" }, }; ParameterComparer compare = new ParameterComparer(); IEnumerable<Parameter> results = dataA.Except(dataB, compare); foreach (var item in results) { Console.WriteLine(item.ToString()); } Console.ReadKey(); } }
Range
指定开始位置,指定个数的连续列表做成。
IEnumerable<int> intSequenceA = Enumerable.Range(1, 5); IEnumerable<int> intSequenceB = Enumerable.Range(-1, 3); IEnumerable<int> intSequenceC = Enumerable.Range(100, 4); foreach (var d in intSequenceA) { Console.WriteLine(d); } Console.WriteLine("========="); foreach (var d in intSequenceB) { Console.WriteLine(d); } Console.WriteLine("========="); foreach (var d in intSequenceC) { Console.WriteLine(d); }
备注:https://www.urablog.xyz/entry/2018/07/10/070000