目录
一、LINQ
1. LINQ介绍
2. 匿名类型
二、方法语法和查询语法
1. 初识查询语法和方法语法。
2. 查询变量
三、查询表达式的结构
1. from子句
2. join子句
3. 查询主体中的from...let...where片段
1.多个from子句
2.let子句
3.多个where子句
4. orderby子句
5. select子句
6. 查询中的匿名类型
7. group子句
8. 查询延续:into子句
四、标准查询运算符
五、将委托作为参数
1. LINQ预定义泛型委托
2.预定义泛型委托和标准运算符配合使用案例
3. Lambda表达式代替委托的情景
代码案例:
internal class Program
{
static void Main(string[] args)
{
//1.数据源
int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
//2.创建查询
IEnumerable query = from n in nums where n > 5 select n;
//3.执行查询
foreach (int n in query)
Console.WriteLine(n);
}
}
上述代码中仅通过创建查询不会检索到任何数据,执行查询是在foreach中发生。(延迟查询)
代码示例:
class Other
{
public static string Name = "光头强";
}
internal class Program
{
static void Main(string[] args)
{
string Major = "体育";
var man = new { Age = 25, Other.Name, Major };
Console.WriteLine("Age:{0}, Name:{1}, Major:{2}", man.Age, man.Name, man.Major);
}
}
internal class Program
{
static void Main(string[] args)
{
int[] ints = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
//查询语法
IEnumerable numsQuery = from n in ints
where n > 4 && n < 8
select n;
//方法语法
IEnumerable methodQuery = ints.Where(x => (x > 4 && x < 8));//返回枚举
//两种形式的组合
int count = (from n in ints where n > 4 && n < 8 select n).Count();//返回单个值
foreach (int i in methodQuery)
Console.Write(i);
Console.WriteLine();
foreach (int i in numsQuery)
Console.Write(i);
Console.WriteLine();
Console.Write(count);
}
}
查询表达式由查询体后的from子句组成。
internal class Program
{
static void Main(string[] args)
{
int[] ints = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var nums = from n in ints
where n > 7 //使用迭代变量n
select n; //使用迭代变量n
foreach (var n in nums)
Console.WriteLine(n);
}
}
class Student
{
public int StID;
public string LastName;
}
class CourseStudent
{
public string CourseName;
public int StID;
}
internal class Program
{
//初始化数组
static Student[] students = new Student[] {
new Student { StID = 1,LastName="光头强" },
new Student { StID = 2,LastName="熊大" },
new Student { StID = 3,LastName="熊二" }
};
static CourseStudent[] courseStudents = new CourseStudent[] {
new CourseStudent { StID = 1,CourseName="体育"},
new CourseStudent { StID = 2,CourseName="历史"},
new CourseStudent { StID = 2,CourseName="化学"},
new CourseStudent { StID = 3,CourseName="化学"},
new CourseStudent { StID = 1,CourseName="历史"},
new CourseStudent { StID = 3,CourseName="体育"},
};
static void Main(string[] args)
{
//查询所有选择了历史课的学生
var query = from s in students
join c in courseStudents on s.StID equals c.StID
where c.CourseName == "历史"
select s.LastName;
foreach (var e in query)
Console.WriteLine(e);
}
}
可选的from...let...where部分是查询主体的第一部分,可以由任意数量的from子句、let子句、where子句来组合。
internal class MyClass
{
static void Main(string[] args)
{
var groupA = new[] { 3, 4, 5, 6 };
var groupB = new[] { 6, 7, 8, 9 };
var someInts = from a in groupA //必需的第一个from子句
from b in groupB //查询主体的第一个from子句
where a > 4 && b <= 8
select new { a, b, sum = a + b };//匿名类型对象
foreach (var e in someInts)
Console.WriteLine(e);
}
}
let子句接受一个表达式的运算并且把它赋值给一个需要在其他运算中使用的标识符。
internal class MyClass
{
static void Main(string[] args)
{
var groupA = new[] { 3, 4, 5, 6 };
var groupB = new[] { 6, 7, 8, 9 };
var someInts = from a in groupA
from b in groupB
let sum = a + b
where sum == 12
select new { a, b, sum };
foreach (var e in someInts)
Console.WriteLine(e);
}
}
where子句根据之后的运算来去除不符合条件的项。
internal class MyClass
{
static void Main(string[] args)
{
var groupA = new[] { 3, 4, 5, 6 };
var groupB = new[] { 6, 7, 8, 9 };
var someInts = from a in groupA
from b in groupB
let sum = a + b
where sum >= 11 //选择sum>=11的
where a == 4 //选择a==4的
select new { a, b, sum };//存放满足两种条件的匿名类
foreach (var e in someInts)
Console.WriteLine(e);
}
}
orderby接受一个表达式,并根据表达式按顺序返回结果项。orderby子句默认升序,可以使用ascending和descending来指定升序还是降序
internal class MyClass
{
static void Main(string[] args)
{
//匿名类型的对象数组
var students = new[]
{
new { Name = "光头强", Age = 25, Course = "体育" },
new { Name = "熊大", Age = 17, Course = "美术" },
new { Name = "熊二", Age = 16, Course = "历史" },
new { Name = "喜羊羊", Age = 13, Course = "历史" },
new { Name = "懒羊羊", Age = 14, Course = "历史" },
new { Name = "沸羊羊", Age = 15, Course = "历史" },
};
var stu = from s in students
orderby s.Age
select s;
foreach ( var student in stu )
Console.WriteLine("{0},{1},{2}",student.Name,student.Age,student.Course);
}
}
select子句指定所选对象的哪部分应该被选择。
internal class MyClass
{
static void Main(string[] args)
{
//匿名类型的对象数组
var students = new[]
{
new { Name = "光头强", Age = 25, Course = "体育" },
new { Name = "熊大", Age = 17, Course = "美术" },
new { Name = "熊二", Age = 16, Course = "历史" },
new { Name = "喜羊羊", Age = 13, Course = "历史" },
new { Name = "懒羊羊", Age = 14, Course = "历史" },
new { Name = "沸羊羊", Age = 15, Course = "历史" },
};
var stu = from s in students
select s.Name; //只选择数据项中的学生名字
foreach ( var student in stu )
Console.WriteLine("{0}",student);
}
}
可以在select子句后创建匿名类型存放指定查询的数据。
internal class MyClass
{
static void Main(string[] args)
{
//匿名类型的对象数组
var students = new[]
{
new { Name = "光头强", Age = 25, Course = "体育" },
new { Name = "熊大", Age = 17, Course = "美术" },
new { Name = "熊二", Age = 16, Course = "历史" },
new { Name = "喜羊羊", Age = 13, Course = "历史" },
new { Name = "懒羊羊", Age = 14, Course = "历史" },
new { Name = "沸羊羊", Age = 15, Course = "历史" },
};
var stu = from s in students
select new { s.Name, s.Age };//创建匿名类型存放需要的数据
foreach ( var student in stu )
Console.WriteLine("{0}\t{1}",student.Name,student.Age);
}
}
group子句把select的对象根据一些标准进行分组。
internal class MyClass
{
static void Main(string[] args)
{
//匿名类型的对象数组
var students = new[]
{
new { Name = "光头强", Age = 25, Course = "体育" },
new { Name = "熊大", Age = 17, Course = "美术" },
new { Name = "熊二", Age = 16, Course = "历史" },
new { Name = "喜羊羊", Age = 13, Course = "历史" },
new { Name = "懒羊羊", Age = 14, Course = "历史" },
new { Name = "沸羊羊", Age = 15, Course = "历史" },
};
var stus = from s in students
group s by s.Course;//根据学科进行分组
foreach (var stu in stus)
{
Console.WriteLine(stu.Key);//分组键
foreach (var s in stu)
Console.WriteLine(" {0},{1}",s.Name,s.Age);
}
}
}
图解:
查询延续子句可以接受查询的一部分结果并赋予一个名字,从而可以在查询的另一部分中使用。
internal class MyClass
{
static void Main(string[] args)
{
int[] groupA = { 1, 2, 3, 4, 5, 6, 7, 8, };
int[] groupB = { 5, 6, 7 };
//将groupA、groupB的联合查询的结果延续一个新名字groupAandB,然后继续新的查询
IEnumerable ints = from a in groupA
join b in groupB on a equals b
into groupAandB
from c in groupAandB
select c;
foreach (int i in ints)
Console.WriteLine(i);
}
}
标准查询运算符由一系列API方法组成,它们可以让我们查询任何.NET数组或集合。
很多LINQ运算符需要我们提供代码来指示运算符如何执行它的操作,我们通过把委托对象作为参数来实现。LINQ定义了套泛型委托类型与标准查询运算符一起使用,即Func委托和Action委托,各有17个成员。
internal class MyClass
{
static bool IsOdd(int x) //委托对象使用的方法
{
return x % 2 == 1;
}
static void Main(string[] args)
{
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Func func = new Func(IsOdd);//谓词:根据对象是否满足某个条件返回true或false
int count = arr.Count(func);
Console.WriteLine("奇数个数为:{0}",count);
}
}
可以选择使用委托来搭配标准运算符的情景:
如果上述两条都不成立,那么就可以使用Lambda表达式来简化
//使用Lambda表达式简化使用委托来获取奇数个数的代码
internal class MyClass
{
static void Main(string[] args)
{
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int count = arr.Count(x => x % 2 == 1);
Console.WriteLine("奇数个数为:{0}",count);
}
}
(注:本章学习总结自《C#图解教程》)