.NET学习(8)语言集成查询 (LINQ)
语言集成查询 (LINQ) 是一系列直接将查询功能集成到 C# 语言的技术统称。
- 用最少的代码对数据源执行筛选、排序和分组操作
- 对不同类型的数据源提供统一的数据访问接口:SQL 数据库、ADO .NET 数据集、XML 文档和流以及 .NET 集合中的数据
LINQ的种类
- LINQ to XML:XML 文档
- LINQ to Entities:ADO.NET 实体框架
- LINQ to Objects:.NET 集合、文件、字符串等
1. LINQ to Objects 的使用
可以使用 LINQ 来查询任何可枚举的集合,例如 List<T>、Array 或 Dictionary<TKey,TValue>。 该集合可以是用户定义的集合,也可以是由 .NET Framework API 返回的集合。
using System;
using System.Linq;
namespace program
{
public class Program
{
public static void Main(string[] args)
{
string[] greetings = {"Hello", "Hi", "How are you"};
var items = from s in greetings
where s.Length >= 5
select s;
foreach(var item in items)
{
Console.WriteLine(item);
}
return;
}
}
}
// output:
// Hello
// How are you
LINQ 查询与传统 foreach 循环相比具有三大优势:
- 它们更简明、更易读,尤其在筛选多个条件时
- 它们使用最少的应用程序代码提供强大的筛选、排序和分组功能
- 无需修改或只需做很小的修改即可将它们移植到其他数据源
LINQ to Objects 的实现基于:
- IEnumerable<T>范型接口
- 序列<sequences>,实现 IEnumerable<T>的集合对象
- 标准查询操作符,就是扩展方法[select where]
IEnumerable
IEnumerable 是可枚举的所有非泛型集合的基接口。它包含一个方法,GetEnumerator ,它将返回 IEnumerator。IEnumerator
IEnumerator 是所有非泛型枚举器的基接口。支持对非泛型集合的简单迭代。
IEnumerator 提供了通过公开循环访问集合的功能Current属性和MoveNext和Reset方法。最佳实践
在自己的集合类上实现 IEnumerable 和 IEnumerator 两个接口,用以支持foreach语法。其中,实现 IEnumerable 不是必要的。
2. 创建可枚举的类
MyEnumerable
public class MyEnumerable: IEnumerable
{
public int StartCountDown;
public IEnumerator GetEnumerator()
{
return new MyEnumerator(this);
}
}
MyEnumerator
public class MyEnumerator: IEnumerator
{
private int cur;
private MyEnumerable owner;
public MyEnumerator(MyEnumerable countdown)
{
owner = countdown;
Reset();
}
public void Reset()
{
cur = owner.StartCountDown;
}
public bool MoveNext()
{
if (cur > 0)
{
cur--;
return true;
}
return false;
}
public object Current { get { return cur; } }
}
Program::Main()
public class Program
{
public static void Main(string[] args)
{
// 一个可枚举类的实例对象
MyEnumerable obj = new MyEnumerable { StartCountDown = 20 };
// 方式一:手动迭代
IEnumerator enu = obj.GetEnumerator();
while (enu.MoveNext())
{
Console.WriteLine((int)enu.Current);
}
// 方式二:使用foreach语法进行迭代
foreach(var i in obj)
{
Console.WriteLine(i);
}
}
}
3. yield的使用
MyYield
public class MyYield: IEnumerable
{
public int StartCountDown;
public IEnumerator GetEnumerator()
{
for(int i=StartCountDown-1; i>=0; i--)
{
yield return i;
}
}
}
Program::Main()
public class Program
{
public static void Main(string[] args)
{
// 一个可枚举类的实例对象
MyYield obj = new MyYield { StartCountDown = 20 };
// 方式一:手动迭代
IEnumerator enu = obj.GetEnumerator();
while (enu.MoveNext())
{
Console.WriteLine((int)enu.Current);
}
// 方式二:使用foreach语法进行迭代
foreach(var i in obj)
{
Console.WriteLine(i);
}
}
}
4. LINQ 标准操作符的使用
示例使用的字符串数组:
string[] array = { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" };
1. Where(1)
Console.WriteLine("--- --- --- 1. Where(1) --- --- ---");
var items1 = array.Where(p => p.StartsWith("t", StringComparison.Ordinal));
foreach(string item in items1)
{
Console.WriteLine(item);
}
/* output:
two
three
ten
*/
2. Where(2)
Console.WriteLine("--- --- --- 2. Where(2) --- --- ---");
var items2 = array.Where((p, i) =>
{
if (i > 2)
return p.StartsWith("t", StringComparison.Ordinal);
else
return false;
});
foreach (string item in items2)
{
Console.WriteLine(item);
}
/* output:
ten
*/
3. 延迟执行
延迟执行是指,在定义items3的时候,并不是真正获取到一个集合,而是在foreach的时候才去获取相应地值。所以,在遍历items3的时候,可以看到对array[2]的修改也体现了出来,即使这个修改发生在定义items3之后。
Console.WriteLine("--- --- --- 3. 延迟执行 --- --- ---");
var items3 = array.Where(p => p.StartsWith("t", StringComparison.Ordinal));
array[2] = "t5000";
foreach (string item in items3)
{
Console.WriteLine(item);
}
/* output:
two
t5000
ten
*/
4. 非延迟执行
由于调用了ToList()方法,在定义items4的时候就已经遍历了array并获取相应的值。所以,后续更改array的操作不会反映到items4中。
Console.WriteLine("--- --- --- 4. 非延迟执行 --- --- ---");
var items4 = array.Where(p => p.StartsWith("t", StringComparison.Ordinal)).ToList();
array[2] = "t6000";
foreach (string item in items4)
{
Console.WriteLine(item);
}
array[2] = "three"; // 复原
/* output:
two
t5000
ten
*/
5. Select(1)
Console.WriteLine("--- --- --- 5. Select(1) --- --- ---");
var items6 = array.Select(p => p.Length);
foreach(int item in items6)
{
Console.WriteLine(item);
}
/* output:
3
3
5
4
4
3
5
5
4
3
*/
6. Select(2)
Console.WriteLine("--- --- --- 6. Select(2) --- --- ---");
var items7 = array.Select((p, i) => new { Index = i, Name = p });
foreach(var item in items7)
{
Console.WriteLine(item);
}
/* output:
{ Index = 0, Name = one }
{ Index = 1, Name = two }
{ Index = 2, Name = three }
{ Index = 3, Name = four }
{ Index = 4, Name = five }
{ Index = 5, Name = six }
{ Index = 6, Name = seven }
{ Index = 7, Name = eight }
{ Index = 8, Name = nine }
{ Index = 9, Name = ten }
*/
7. SelectMany
Console.WriteLine("--- --- --- 7. SelectMany --- --- ---");
var items8 = array.SelectMany(p => p.ToCharArray());
foreach (var item in items8)
{
Console.WriteLine(item);
}
/* output:
o
n
e
t
w
o
……
*/
8. Take
Console.WriteLine("--- --- --- 8. Take --- --- ---");
var items9 = array.Take(3);
foreach (var item in items9)
{
Console.WriteLine(item);
}
/* output:
one
two
three
*/
9. TakeWhile
Console.WriteLine("--- --- --- 9. TakeWhile --- --- ---");
var items10 = array.TakeWhile(p => p.Length < 4);
foreach (var item in items10)
{
Console.WriteLine(item);
}
/* output:
one
two
*/
10. Skip
Console.WriteLine("--- --- --- 10. Skip --- --- ---");
var items11 = array.Skip(3);
foreach (var item in items11)
{
Console.WriteLine(item);
}
/* output:
four
five
six
seven
eight
nine
ten
*/
11. SkipWhile
Console.WriteLine("--- --- --- 11. SkipWhile --- --- ---");
var items12 = array.SkipWhile(p => p.Length < 4);
foreach (var item in items12)
{
Console.WriteLine(item);
}
/* output:
three
four
five
six
seven
eight
nine
ten
*/
12. OrderBy(1)
Console.WriteLine("--- --- --- 12. OrderBy(1) --- --- ---");
var items13 = array.OrderBy(p => p.Length);
foreach (var item in items13)
{
Console.WriteLine(item);
}
/* output:
one
two
six
ten
four
five
nine
three
seven
eight
*/
13. OrderBy(2)
Console.WriteLine("--- --- --- 13. OrderBy(2) --- --- ---");
var items14 = array.OrderBy(p => p.Length).Take(5);
foreach (var item in items14)
{
Console.WriteLine(item);
}
/* output:
one
two
six
ten
four
*/
5. 连接操作(Join)
两个类,Student和Score
public class Student
{
public int Id;
public string Name;
public int Age;
}
public class Score
{
public int StudentId;
public float English;
public float Maths;
}
Program::Main()
public class Program
{
public static void Main(string[] args)
{
// 数据初始化
Student[] students = new Student[]
{
new Student{Id=1, Name="1", Age=20},
new Student{Id=2, Name="2", Age=19},
new Student{Id=3, Name="3", Age=21},
new Student{Id=4, Name="4", Age=20}
};
Score[] scores = new Score[]
{
new Score{StudentId=1, English=90, Maths=80},
new Score{StudentId=1, English=91, Maths=85},
new Score{StudentId=1, English=92, Maths=86},
new Score{StudentId=1, English=93, Maths=82}
};
// 查询 1
Console.WriteLine("--- list 1 ---");
var list1 = students.Join(scores, o => o.Id, i => i.StudentId,
(o, i) => new { o.Name, i.English, i.Maths });
foreach(var ele in list1)
{
Console.WriteLine(ele);
}
// 查询 2
Console.WriteLine("--- list 2 ---");
var list2 = from o in students
from i in scores
where o.Id == i.StudentId
orderby i.Maths
select new { o.Name, i.English, i.Maths };
foreach (var ele in list2)
{
Console.WriteLine(ele);
}
}
}
/* output
--- list 1 ---
{ Name = 1, English = 90, Maths = 80 }
{ Name = 1, English = 91, Maths = 85 }
{ Name = 1, English = 92, Maths = 86 }
{ Name = 1, English = 93, Maths = 82 }
--- list 2 ---
{ Name = 1, English = 90, Maths = 80 }
{ Name = 1, English = 93, Maths = 82 }
{ Name = 1, English = 91, Maths = 85 }
{ Name = 1, English = 92, Maths = 86 }
*/
转载于:https://www.jianshu.com/p/2c9a269099c7
上一篇: 第十二章多态
下一篇: CSS-边距2-实现一个三角形