Linq
在C#
中提供语言级查询功能和高阶函数 API,以便能够编写具有很高表达力度的声明性代码。使用Linq
能够让我们的代码更加简洁。下面先来看一个问题:现在有一个数组,如下所示:
int[] nums = { 8, 1, 9, 4, 3, 6, 7 };
现在我们希望找出这个数组中的偶数
,然后将它们降序输出,一般我们会这么写:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int[] nums = { 8, 1, 9, 4, 3, 6, 7 };
// 查找偶数
List<int> list = new List<int>();
foreach (int num in nums)
{
if (num % 2 == 0)
{
list.Add(num);
}
}
// 排序反转
list.Sort();
list.Reverse();
// 输出偶数
foreach (int num in list)
{
Console.WriteLine(num);
}
Console.ReadKey();
}
}
}
虽然能够实现功能,但这段代码显得有些复杂,这个时候如果使用Linq
将会非简单,代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int[] nums = { 8, 1, 9, 4, 3, 6, 7 };
IEnumerable<int> query = from num in nums
where num % 2 == 0
orderby num descending
select num;
foreach (int num in query)
{
Console.WriteLine(num);
}
Console.ReadKey();
}
}
}
输出结果如下所示:
8
6
4
在查询表达式中,select
子句可以指定将在执行查询时产生的值的类型。所有的Linq
查询语句必须以select
或者group
结尾。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Student> students = new List<Student>();
students.Add(new Student() { Id = 1, Name = "张三", Gender = "男", Age = 23 });
students.Add(new Student() { Id = 2, Name = "李四", Gender = "女", Age = 27 });
students.Add(new Student() { Id = 3, Name = "王五", Gender = "男", Age = 21 });
students.Add(new Student() { Id = 4, Name = "赵六", Gender = "女", Age = 25 });
IEnumerable<Student> query = from student in students
select student;
foreach (var item in query)
{
Console.WriteLine(item.Id + "," + item.Name + "," + item.Gender + "," + item.Age);
}
Console.ReadKey();
}
}
class Student
{
///
/// 编号
///
public int Id { get; set; }
///
/// 姓名
///
public string Name { get; set; }
///
/// 性别
///
public string Gender { get; set; }
///
/// 年龄
///
public int Age { get; set; }
}
}
输出结果如下所示:
1,张三,男,23
2,李四,女,27
3,王五,男,21
4,赵六,女,25
很多时候我们需要设置查询条件,这时就可以使用where
字句。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Student> students = new List<Student>();
students.Add(new Student() { Id = 1, Name = "张三", Gender = "男", Age = 23 });
students.Add(new Student() { Id = 2, Name = "李四", Gender = "女", Age = 27 });
students.Add(new Student() { Id = 3, Name = "王五", Gender = "男", Age = 21 });
students.Add(new Student() { Id = 4, Name = "赵六", Gender = "女", Age = 25 });
IEnumerable<Student> query = from student in students
where student.Gender == "男"
select student;
foreach (var item in query)
{
Console.WriteLine(item.Id + "," + item.Name + "," + item.Gender + "," + item.Age);
}
Console.ReadKey();
}
}
class Student
{
///
/// 编号
///
public int Id { get; set; }
///
/// 姓名
///
public string Name { get; set; }
///
/// 性别
///
public string Gender { get; set; }
///
/// 年龄
///
public int Age { get; set; }
}
}
输出结果如下所示:
1,张三,男,23
3,王五,男,21
let
可以创建一个范围变量来存储结果,变量被创建后,不能修改或把其他表达式的结果重新赋值给它。此范围变量可以再后续的Linq
中使用。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Student> students = new List<Student>();
students.Add(new Student() { Id = 1, Name = "张三", Gender = "男", Age = 23 });
students.Add(new Student() { Id = 2, Name = "李四", Gender = "女", Age = 27 });
students.Add(new Student() { Id = 3, Name = "王五", Gender = "男", Age = 21 });
students.Add(new Student() { Id = 4, Name = "赵六", Gender = "女", Age = 25 });
IEnumerable<Student> query = from student in students
let gender = "男"
let age = 22
where student.Gender == gender && student.Age > age
select student;
foreach (var item in query)
{
Console.WriteLine(item.Id + "," + item.Name + "," + item.Gender + "," + item.Age);
}
Console.ReadKey();
}
}
class Student
{
///
/// 编号
///
public int Id { get; set; }
///
/// 姓名
///
public string Name { get; set; }
///
/// 性别
///
public string Gender { get; set; }
///
/// 年龄
///
public int Age { get; set; }
}
}
输出结果如下所示:
1,张三,男,23
根据字段进行排序也是常见的操作,Linq
中可以使用orderby
来实现排序。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Student> students = new List<Student>();
students.Add(new Student() { Id = 1, Name = "张三", Gender = "男", Age = 23 });
students.Add(new Student() { Id = 2, Name = "李四", Gender = "女", Age = 27 });
students.Add(new Student() { Id = 3, Name = "王五", Gender = "男", Age = 21 });
students.Add(new Student() { Id = 4, Name = "赵六", Gender = "女", Age = 25 });
IEnumerable<Student> query = from student in students
where student.Gender == "男"
orderby student.Age
select student;
foreach (var item in query)
{
Console.WriteLine(item.Id + "," + item.Name + "," + item.Gender + "," + item.Age);
}
Console.ReadKey();
}
}
class Student
{
///
/// 编号
///
public int Id { get; set; }
///
/// 姓名
///
public string Name { get; set; }
///
/// 性别
///
public string Gender { get; set; }
///
/// 年龄
///
public int Age { get; set; }
}
}
输出结果如下所示:
3,王五,男,21
1,张三,男,23
一般使用group-by
实现分组查询操作。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Student> students = new List<Student>();
students.Add(new Student() { Id = 1, Name = "张三", Gender = "男", Age = 23 });
students.Add(new Student() { Id = 2, Name = "李四", Gender = "女", Age = 27 });
students.Add(new Student() { Id = 3, Name = "王五", Gender = "男", Age = 21 });
students.Add(new Student() { Id = 4, Name = "赵六", Gender = "女", Age = 25 });
IEnumerable<IGrouping<string, Student>> query = from student in students
group student by student.Gender;
foreach (var group in query)
{
Console.WriteLine(group.Key);
foreach (var item in group)
{
Console.WriteLine(item.Id + "," + item.Name + "," + item.Gender + "," + item.Age);
}
}
Console.ReadKey();
}
}
class Student
{
///
/// 编号
///
public int Id { get; set; }
///
/// 姓名
///
public string Name { get; set; }
///
/// 性别
///
public string Gender { get; set; }
///
/// 年龄
///
public int Age { get; set; }
}
}
输出结果如下所示:
男
1,张三,男,23
3,王五,男,21
女
2,李四,女,27
4,赵六,女,25
我们也可以使用group-by-into
实现分组查询。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Student> students = new List<Student>();
students.Add(new Student() { Id = 1, Name = "张三", Gender = "男", Age = 23 });
students.Add(new Student() { Id = 2, Name = "李四", Gender = "女", Age = 27 });
students.Add(new Student() { Id = 3, Name = "王五", Gender = "男", Age = 21 });
students.Add(new Student() { Id = 4, Name = "赵六", Gender = "女", Age = 25 });
IEnumerable<IGrouping<string, Student>> query = from student in students
group student by student.Gender into groups
where groups.Key == "男"
select groups;
foreach (var group in query)
{
foreach (var item in group)
{
Console.WriteLine(item.Id + "," + item.Name + "," + item.Gender + "," + item.Age);
}
}
Console.ReadKey();
}
}
class Student
{
///
/// 编号
///
public int Id { get; set; }
///
/// 姓名
///
public string Name { get; set; }
///
/// 性别
///
public string Gender { get; set; }
///
/// 年龄
///
public int Age { get; set; }
}
}
输出结果如下所示:
1,张三,男,23
3,王五,男,21
内连接查询就是查找两个表中能够匹配的数据,Linq
使用join
实现内连接查询。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Class> classes = new List<Class>();
classes.Add(new Class() { Id = 1, ClassName = "一班" });
classes.Add(new Class() { Id = 2, ClassName = "二班" });
classes.Add(new Class() { Id = 3, ClassName = "三班" });
classes.Add(new Class() { Id = 4, ClassName = "四班" });
List<Student> students = new List<Student>();
students.Add(new Student() { Id = 1, StudentName = "张三", Gender = "男", Age = 23, ClassId = 1 });
students.Add(new Student() { Id = 2, StudentName = "李四", Gender = "女", Age = 27, ClassId = 2 });
students.Add(new Student() { Id = 3, StudentName = "王五", Gender = "男", Age = 21, ClassId = 3 });
students.Add(new Student() { Id = 4, StudentName = "赵六", Gender = "女", Age = 25, ClassId = 5 });
IEnumerable<Student> query = from s in students
join c in classes on s.ClassId equals c.Id
select s;
foreach (var item in query)
{
Console.WriteLine(item.Id + "," + item.StudentName + "," + item.Gender + "," + item.Age + "," + item.ClassId);
}
Console.ReadKey();
}
}
class Class
{
///
/// 编号
///
public int Id { get; set; }
///
/// 名称
///
public string ClassName { get; set; }
}
class Student
{
///
/// 编号
///
public int Id { get; set; }
///
/// 姓名
///
public string StudentName { get; set; }
///
/// 性别
///
public string Gender { get; set; }
///
/// 年龄
///
public int Age { get; set; }
///
/// 班级编号
///
public int ClassId { get; set; }
}
}
输出结果如下所示:
1,张三,男,23,1
2,李四,女,27,2
3,王五,男,21,3
组连接是与分组查询是一样的。即根据分组得到结果。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Class> classes = new List<Class>();
classes.Add(new Class() { Id = 1, ClassName = "一班" });
classes.Add(new Class() { Id = 2, ClassName = "二班" });
classes.Add(new Class() { Id = 3, ClassName = "三班" });
classes.Add(new Class() { Id = 4, ClassName = "四班" });
List<Student> students = new List<Student>();
students.Add(new Student() { Id = 1, StudentName = "张三", Gender = "男", Age = 23, ClassId = 1 });
students.Add(new Student() { Id = 2, StudentName = "李四", Gender = "女", Age = 27, ClassId = 2 });
students.Add(new Student() { Id = 3, StudentName = "王五", Gender = "男", Age = 21, ClassId = 3 });
students.Add(new Student() { Id = 4, StudentName = "赵六", Gender = "女", Age = 25, ClassId = 4 });
var query = from c in classes
join s in students on c.Id equals s.ClassId into result
select new
{
ClassName = c.ClassName,
Students = result
};
foreach (var obj in query)
{
Console.WriteLine(obj.ClassName);
foreach (var item in obj.Students)
{
Console.WriteLine(item.Id + "," + item.StudentName + "," + item.Gender + "," + item.Age);
}
}
Console.ReadKey();
}
}
class Class
{
///
/// 编号
///
public int Id { get; set; }
///
/// 名称
///
public string ClassName { get; set; }
}
class Student
{
///
/// 编号
///
public int Id { get; set; }
///
/// 姓名
///
public string StudentName { get; set; }
///
/// 性别
///
public string Gender { get; set; }
///
/// 年龄
///
public int Age { get; set; }
///
/// 班级编号
///
public int ClassId { get; set; }
}
}
输出结果如下所示:
一班
1,张三,男,23
二班
2,李四,女,27
三班
3,王五,男,21
四班
4,赵六,女,25
使用左连接查询需要注意空值的判断,否则会引发异常。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Class> classes = new List<Class>();
classes.Add(new Class() { Id = 1, ClassName = "一班" });
classes.Add(new Class() { Id = 2, ClassName = "二班" });
classes.Add(new Class() { Id = 3, ClassName = "三班" });
classes.Add(new Class() { Id = 4, ClassName = "四班" });
List<Student> students = new List<Student>();
students.Add(new Student() { Id = 1, StudentName = "张三", Gender = "男", Age = 23, ClassId = 1 });
students.Add(new Student() { Id = 2, StudentName = "李四", Gender = "女", Age = 27, ClassId = 2 });
students.Add(new Student() { Id = 3, StudentName = "王五", Gender = "男", Age = 21, ClassId = 3 });
students.Add(new Student() { Id = 4, StudentName = "赵六", Gender = "女", Age = 25, ClassId = 5 });
var query = from c in classes
join s in students on c.Id equals s.ClassId into result
from r in result.DefaultIfEmpty()
select new
{
ClassName = c.ClassName,
StudentName = r != null ? r.StudentName : "学生姓名未知",
Gender = r != null ? r.Gender : "学生性别未知"
};
foreach (var item in query)
{
Console.WriteLine(item.ClassName + "," + item.StudentName);
}
Console.ReadKey();
}
}
class Class
{
///
/// 编号
///
public int Id { get; set; }
///
/// 名称
///
public string ClassName { get; set; }
}
class Student
{
///
/// 编号
///
public int Id { get; set; }
///
/// 姓名
///
public string StudentName { get; set; }
///
/// 性别
///
public string Gender { get; set; }
///
/// 年龄
///
public int Age { get; set; }
///
/// 班级编号
///
public int ClassId { get; set; }
}
}
输出结果如下所示:
一班,张三
二班,李四
三班,王五
四班,学生姓名未知
交叉连接很简单,就是两张表的逐一匹配。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Class> classes = new List<Class>();
classes.Add(new Class() { Id = 1, ClassName = "一班" });
classes.Add(new Class() { Id = 2, ClassName = "二班" });
classes.Add(new Class() { Id = 3, ClassName = "三班" });
classes.Add(new Class() { Id = 4, ClassName = "四班" });
List<Student> students = new List<Student>();
students.Add(new Student() { Id = 1, StudentName = "张三", Gender = "男", Age = 23, ClassId = 1 });
students.Add(new Student() { Id = 2, StudentName = "李四", Gender = "女", Age = 27, ClassId = 2 });
students.Add(new Student() { Id = 3, StudentName = "王五", Gender = "男", Age = 21, ClassId = 3 });
students.Add(new Student() { Id = 4, StudentName = "赵六", Gender = "女", Age = 25, ClassId = 5 });
var query = from s in students
from c in classes
select new
{
ClassName = c.ClassName,
StudentName = s.StudentName,
Gender = s.Gender
};
foreach (var item in query)
{
Console.WriteLine(item.ClassName + "," + item.StudentName + "," + item.Gender);
}
Console.ReadKey();
}
}
class Class
{
///
/// 编号
///
public int Id { get; set; }
///
/// 名称
///
public string ClassName { get; set; }
}
class Student
{
///
/// 编号
///
public int Id { get; set; }
///
/// 姓名
///
public string StudentName { get; set; }
///
/// 性别
///
public string Gender { get; set; }
///
/// 年龄
///
public int Age { get; set; }
///
/// 班级编号
///
public int ClassId { get; set; }
}
}
输出结果如下所示:
一班,张三,男
二班,张三,男
三班,张三,男
四班,张三,男
一班,李四,女
二班,李四,女
三班,李四,女
四班,李四,女
一班,王五,男
二班,王五,男
三班,王五,男
四班,王五,男
一班,赵六,女
二班,赵六,女
三班,赵六,女
四班,赵六,女