前言
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
1、select
在查詢表達式中,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
{
/// <summary>
/// 編號
/// </summary>
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 性別
/// </summary>
public string Gender { get; set; }
/// <summary>
/// 年齡
/// </summary>
public int Age { get; set; }
}
}
輸出結果如下所示:
1,張三,男,23
2,李四,女,27
3,王五,男,21
4,趙六,女,25
2、where
很多時候我們需要設置查詢條件,這時就可以使用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
{
/// <summary>
/// 編號
/// </summary>
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 性別
/// </summary>
public string Gender { get; set; }
/// <summary>
/// 年齡
/// </summary>
public int Age { get; set; }
}
}
輸出結果如下所示:
1,張三,男,23
3,王五,男,21
3、let
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
{
/// <summary>
/// 編號
/// </summary>
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 性別
/// </summary>
public string Gender { get; set; }
/// <summary>
/// 年齡
/// </summary>
public int Age { get; set; }
}
}
輸出結果如下所示:
1,張三,男,23
4、orderby
根據字段進行排序也是常見的操作,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
{
/// <summary>
/// 編號
/// </summary>
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 性別
/// </summary>
public string Gender { get; set; }
/// <summary>
/// 年齡
/// </summary>
public int Age { get; set; }
}
}
輸出結果如下所示:
3,王五,男,21
1,張三,男,23
5、group-by
一般使用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
{
/// <summary>
/// 編號
/// </summary>
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 性別
/// </summary>
public string Gender { get; set; }
/// <summary>
/// 年齡
/// </summary>
public int Age { get; set; }
}
}
輸出結果如下所示:
男
1,張三,男,23
3,王五,男,21
女
2,李四,女,27
4,趙六,女,25
6、group-by-into
我們也可以使用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
{
/// <summary>
/// 編號
/// </summary>
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 性別
/// </summary>
public string Gender { get; set; }
/// <summary>
/// 年齡
/// </summary>
public int Age { get; set; }
}
}
輸出結果如下所示:
1,張三,男,23
3,王五,男,21
7、內連接查詢
內連接查詢就是查找兩個表中能夠匹配的數據,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
{
/// <summary>
/// 編號
/// </summary>
public int Id { get; set; }
/// <summary>
/// 名稱
/// </summary>
public string ClassName { get; set; }
}
class Student
{
/// <summary>
/// 編號
/// </summary>
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string StudentName { get; set; }
/// <summary>
/// 性別
/// </summary>
public string Gender { get; set; }
/// <summary>
/// 年齡
/// </summary>
public int Age { get; set; }
/// <summary>
/// 班級編號
/// </summary>
public int ClassId { get; set; }
}
}
輸出結果如下所示:
1,張三,男,23,1
2,李四,女,27,2
3,王五,男,21,3
8、組連接查詢
組連接是與分組查詢是一樣的。即根據分組得到結果。
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
{
/// <summary>
/// 編號
/// </summary>
public int Id { get; set; }
/// <summary>
/// 名稱
/// </summary>
public string ClassName { get; set; }
}
class Student
{
/// <summary>
/// 編號
/// </summary>
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string StudentName { get; set; }
/// <summary>
/// 性別
/// </summary>
public string Gender { get; set; }
/// <summary>
/// 年齡
/// </summary>
public int Age { get; set; }
/// <summary>
/// 班級編號
/// </summary>
public int ClassId { get; set; }
}
}
輸出結果如下所示:
一班
1,張三,男,23
二班
2,李四,女,27
三班
3,王五,男,21
四班
4,趙六,女,25
9、左連接查詢
使用左連接查詢需要注意空值的判斷,否則會引發異常。
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
{
/// <summary>
/// 編號
/// </summary>
public int Id { get; set; }
/// <summary>
/// 名稱
/// </summary>
public string ClassName { get; set; }
}
class Student
{
/// <summary>
/// 編號
/// </summary>
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string StudentName { get; set; }
/// <summary>
/// 性別
/// </summary>
public string Gender { get; set; }
/// <summary>
/// 年齡
/// </summary>
public int Age { get; set; }
/// <summary>
/// 班級編號
/// </summary>
public int ClassId { get; set; }
}
}
輸出結果如下所示:
一班,張三
二班,李四
三班,王五
四班,學生姓名未知
10、交叉連接
交叉連接很簡單,就是兩張表的逐一匹配。
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
{
/// <summary>
/// 編號
/// </summary>
public int Id { get; set; }
/// <summary>
/// 名稱
/// </summary>
public string ClassName { get; set; }
}
class Student
{
/// <summary>
/// 編號
/// </summary>
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string StudentName { get; set; }
/// <summary>
/// 性別
/// </summary>
public string Gender { get; set; }
/// <summary>
/// 年齡
/// </summary>
public int Age { get; set; }
/// <summary>
/// 班級編號
/// </summary>
public int ClassId { get; set; }
}
}
輸出結果如下所示:
一班,張三,男
二班,張三,男
三班,張三,男
四班,張三,男
一班,李四,女
二班,李四,女
三班,李四,女
四班,李四,女
一班,王五,男
二班,王五,男
三班,王五,男
四班,王五,男
一班,趙六,女
二班,趙六,女
三班,趙六,女
四班,趙六,女