C# LINQ 排序详解 —— OrderBy / OrderByDescending / ThenBy / ThenByDescending


C# LINQ 排序详解 ------ OrderBy / OrderByDescending / ThenBy / ThenByDescending

在 C# 中,对集合进行排序最常用的方式是 LINQ 提供的排序运算符:OrderBy、OrderByDescending、ThenBy、ThenByDescending。它们支持单级排序和多级组合排序,且不会修改原集合,返回新的有序序列。


一、核心 API 速览

方法 说明 返回值类型
OrderBy(key) 按指定键升序排列(主排序) IOrderedEnumerable<T>
OrderByDescending(key) 按指定键降序排列(主排序) IOrderedEnumerable<T>
ThenBy(key) 在主排序基础上按指定键升序二次排序 IOrderedEnumerable<T>
ThenByDescending(key) 在主排序基础上按指定键降序二次排序 IOrderedEnumerable<T>

⚠️ ThenBy / ThenByDescending 只能 跟在 OrderBy / OrderByDescending 后面调用,因为它们扩展的是 IOrderedEnumerable<T>,而非普通 IEnumerable<T>。


二、准备测试数据

csharp 复制代码
using System;
using System.Collections.Generic;
using System.Linq;

class Student
{
    public string Name { get; set; }
    public int Age { get; set; }
    public double Score { get; set; }
}

var students = new List<Student>
{
    new Student { Name = "张三", Age = 20, Score = 88 },
    new Student { Name = "李四", Age = 22, Score = 95 },
    new Student { Name = "王五", Age = 20, Score = 95 },
    new Student { Name = "赵六", Age = 22, Score = 88 }
};

三、基础用法 ------ 单字段排序

3.1 升序 OrderBy

csharp 复制代码
// 按年龄升序
var r1 = students
    .OrderBy(s => s.Age)
    .ToList();

等价查询表达式语法:

csharp 复制代码
var r1 = (from s in students
          orderby s.Age
          select s).ToList();

3.2 降序 OrderByDescending

csharp 复制代码
// 按分数降序
var r2 = students
    .OrderByDescending(s => s.Score)
    .ToList();

等价查询表达式:

csharp 复制代码
var r2 = (from s in students
          orderby s.Score descending
          select s).ToList();

四、多级排序 ------ ThenBy / ThenByDescending

常见需求:先按年龄升序,年龄相同再按分数降序,分数还相同再按姓名升序

csharp 复制代码
var r3 = students
    .OrderBy(s => s.Age)                  // 主排序:年龄 ↑
    .ThenByDescending(s => s.Score)       // 次排序:分数 ↓
    .ThenBy(s => s.Name)                  // 再次排序:姓名 ↑
    .ToList();

查询结果顺序为:

姓名 年龄 分数
张三 20 88
王五 20 95
赵六 22 88
李四 22 95

等价查询表达式(逗号分隔多条件):

csharp 复制代码
var r3 = (from s in students
          orderby s.Age, s.Score descending, s.Name
          select s).ToList();

五、常见误区

❌ 连续调用两个 OrderBy

csharp 复制代码
// 错误理解:以为先按 Age 排再按 Score 排
var wrong = students
    .OrderBy(s => s.Age)
    .OrderBy(s => s.Score);   // ← 这会【重置】主排序,Age 的排序被丢弃!

✅ 正确做法:只有第一个用 OrderBy,后续必须用 ThenBy。


❌ 对字符串按长度排序时忘记指定 keySelector

csharp 复制代码
string[] fruits = { "apple", "banana", "pear", "watermelon" };

// 按字符串长度升序
var r = fruits.OrderBy(f => f.Length).ToList();
// 结果:pear(4), apple(5), banana(6), watermelon(10)

六、自定义比较器(IComparer)

如需特殊规则(如中文按拼音、忽略大小写等):

csharp 复制代码
var r = students
    .OrderBy(s => s.Name, StringComparer.CurrentCultureIgnoreCase)
    .ToList();

也可实现自定义 IComparer<T> 传入 OrderBy / ThenBy。


七、关键特性总结

  • ♻️ 延迟执行(Deferred Execution) :排序在遍历(foreach / ToList())时才真正执行
  • 🔒 稳定排序:相等键的元素保留原始相对顺序
  • 📦 原集合不变 :返回新 IOrderedEnumerable<T> 序列
  • 🔗 链式调用 :支持无限级 ThenBy / ThenByDescending

八、一句话记忆

排序永远只有一个 OrderBy/OrderByDescending(主排序),其余次要条件全用 ThenBy/ThenByDescending 追加。


相关推荐
cpp_w37 分钟前
C#基础3- 面向对象中级应用3
后端·c#
weixin_3077791338 分钟前
C++代码实现MATLAB中的spectralcluster函数功能
开发语言·c++·算法·matlab
鸽鸽程序猿38 分钟前
【项目】【在线判题系统】c端:竞赛报名
c语言·开发语言
Wang's Blog42 分钟前
Java 项目实战: 交友项目 - 个人资料管理的需求分析与接口设计
java·开发语言·交友
1024奇点1 小时前
【仓颉语言入门 · 第二篇 第 8 课】
开发语言·数据库·ide·mysql·开源
gopher95111 小时前
RUST:序列化与反序列化 serde + derive 详解
开发语言·后端·rust
H.莓飛1 小时前
【Linux】自主 Shell
linux·运维·服务器·c语言·开发语言·visual studio
熊猫钓鱼>_>1 小时前
Kotlin Multiplatform for OpenHarmony 实战:kotlinx-coroutines 结构化并发适配
开发语言·kotlin·agent·harmonyos·openharmony·适配·华为云码道
步步为营DotNet2 小时前
Async 状态机要搬进运行时了:.NET 10 Runtime Async 实测,快的地方快 1.5 倍,贵的地方贵 5 倍
性能优化·c#·.net·async·runtime
沫璃染墨2 小时前
《Qt从零入门系列(十四):QThread多线程详解——从线程创建到客户端阻塞处理》
开发语言·c++·笔记·qt·ui·交互·线程