linq to objects 查询表达式
程序员文章站
2022-06-11 22:42:21
...
首先定义数据源
//学生类
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public int classId { get; set; }
public static List<Student> GetStudent()
{
return new List<Student>() {
new Student() { Id = 1000, Name = "张三", Age = 25,,classId=1},
new Student() { Id = 1002, Name = "李四", Age = 18,classId=2 },
new Student() { Id = 1004, Name = "王五", Age = 18, classId=2 },
new Student() { Id = 1006, Name = "赵六", Age = 12,classId=1}
};
}
}
//班级类
public class Classes
{
public int Id { get; set; }
public string Name { get; set; }
public static List<Classes> GetClasses()
{
return new List<Classes>() {
new Classes() { Id = 1, Name = "软件工程"},
new Classes() { Id = 2, Name = "计算机" }
};
}
}
【1】where子句 过滤
查询表达式:
var query = from p in Student.GetStudent()
where p.Age < 18
select p;
点标记:
var query = Student.GetStudent().Where(p => p.Age < 18).Select(p => p);
点标记的select可以去掉,查询表达式中的p称为范围变量
Cast、OfType和显式类型的变量
linq不能处理ArrayList或者object[] 的查询,但可以使用Cast、OfType来解决这个问题,Cast通过把每个元素都转换成目标类型(遇到不是正确类型的任何元素的时候,就会出错)来处理,而OfType首先进行一个测试,以跳过任何具有错误类型的元素。
ArrayList list = new ArrayList { "a","b","c"};
IEnumerable<string> strings = list.Cast<string>();
foreach (var item in strings)
{
Console.WriteLine(item);
}
list = new ArrayList { 5, 8, 's', "dd" };
IEnumerable<int> ints = list.OfType<int>();
foreach (var item in ints)
{
Console.WriteLine(item);
}
使用显示类型的范围变量来自动调用Cast
ArrayList list = new ArrayList { "abcdef","bcde","cdef"};
var query = from string p in list
select p.Substring(0, 3);
【2】orderby子句 排序
查询表达式:
var query = from p in Student.GetStudent()
orderby p.Age ascending,p.Id descending
select p;
点标记:
var query = Student.GetStudent().OrderBy(p => p.Age).ThenByDescending(p => p.Id);
【3】let子句 透明标识符
var result = from p in Student.GetStudent()
//透明标识符 let , 避免了计算两次姓名的字符数
let length = p.Name.Length
orderby length
select new { Name=p.Name ,Length=length };
foreach (var item in result)
{
Console.WriteLine(item.Length + ":" + item.Name);
}
【4】join子句 内链接
查询表达式:
var query = from p in Student.GetStudent()
join q in Classes.GetClasses()
on p.classId equals q.Id
select new { ClassName=q.Name,StudentName=p.Name};
点标记:
var query = Student.GetStudent().Join(Classes.GetClasses(), p => p.classId, q => q.Id, (p, q) => new { ClassName = q.Name, StudentName = p.Name });
【5】join…into子句 分组连接
查询表达式:
var query = from p in Classes.GetClasses()
join q in Student.GetStudent()
on p.Id equals q.classId into groupedStudent
select new {studentCount = groupedStudent.Count(), classes = p };
foreach (var item in query)
{
Console.WriteLine($"班级:{item.classes.Name},学生数量:{item.studentCount}");
}
点标记:
var query = Classes.GetClasses().GroupJoin(Student.GetStudent(), p => p.Id, q => q.classId, (p, q) => new { studentCount = q.Count(), classes = p });
【6】from子句 交叉连接和合并序列
查询表达式:
var query = from p in Student.GetStudent()
from q in Classes.GetClasses()
select new { student = p, classes = q };
foreach (var item in query)
{
Console.WriteLine($"学生姓名:{item.student.Name} 班级:{item.classes.Name}");
}
运行结果:
学生姓名:张三 班级:软件工程
学生姓名:张三 班级:计算机
学生姓名:李四 班级:软件工程
学生姓名:李四 班级:计算机
学生姓名:王五 班级:软件工程
学生姓名:王五 班级:计算机
学生姓名:赵六 班级:软件工程
学生姓名:赵六 班级:计算机
点标识:
var query = Student.GetStudent().SelectMany(p => Classes.GetClasses(), (p, q) => new { student = p, classes = q });
foreach (var item in query)
{
Console.WriteLine($"学生姓名:{item.student.Name} 班级:{item.classes.Name}");
}
【7】group…by子句 分组
查询表达式:
var query = from p in Student.GetStudent()
group p by p.Age;
foreach (var item in query)
{
Console.WriteLine($"{item.Key}岁的学生数量:{item.Count()}");
}
点标记:
var query = Student.GetStudent().GroupBy(p => p.Age);
foreach (var item in query)
{
Console.WriteLine($"{item.Key}岁的学生数量:{item.Count()}");
}
【8】查询延续
把表达式的结果用作另外一个查询表达式的初始序列 上下文关键字into 并作为新的范围变量提供一个名称,上一个表达式的范围变量将不能再使用。
查询表达式:
var query = from p in Student.GetStudent()
group p by p.Age into grouped
select new { Age=grouped.Key,Count=grouped.Count()};
foreach (var item in query)
{
Console.WriteLine($"{item.Age}岁的学生数量:{item.Count}");
}
点标记:
var query = Student.GetStudent().GroupBy(p => p.Age).Select(grouped => new { Age = grouped.Key, Count = grouped.Count() });
foreach (var item in query)
{
Console.WriteLine($"{item.Age}岁的学生数量:{item.Count}");
}
但join…into 不是延续 join..into可以使用所有的早期的范围变量,延续会清除之前的范围变量,只有在延续中声明的范围变量才能在供后续使用。
总结:所有的查询表达式都可以转换成点标记的形式,但所有的点标记不一定可以转换成查询表达式,例如点标记的Reverse、ToDictionary就没有对应的查询表达式,至于查询表达式与点标记如何选择,就看你自己的编码习惯了。