欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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就没有对应的查询表达式,至于查询表达式与点标记如何选择,就看你自己的编码习惯了。