目录
[方法一:使用 LINQ(OrderBy / ThenBy)](#方法一:使用 LINQ(OrderBy / ThenBy))
[方法二:使用 List.Sort + Lambda 表达式](#方法二:使用 List.Sort + Lambda 表达式)
[方法三:使用 IComparer 接口(适合复杂/复用逻辑)](#方法三:使用 IComparer 接口(适合复杂/复用逻辑))
[方法四:使用 ComparisonChain 风格(第三方库或自定义辅助类)](#方法四:使用 ComparisonChain 风格(第三方库或自定义辅助类))

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。
在 C# 中,对 List<T> 进行多属性(多条件)排序主要有两种主流方式:LINQ 链式调用 (推荐,代码可读性高)和 **List.Sort 自定义比较器**(性能更高,原地排序)。
假设我们有以下数据模型:
public 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 = "Alice", Age = 20, Score = 85.5 },
new Student { Name = "Bob", Age = 20, Score = 90.0 },
new Student { Name = "Charlie", Age = 19, Score = 85.5 },
new Student { Name = "David", Age = 20, Score = 85.5 }
};
方法一:使用 LINQ(OrderBy / ThenBy)
这是最直观、易读的方式。它不会修改原列表,而是返回一个新的排序后的列表。
OrderBy/OrderByDescending:用于第一个排序条件。ThenBy/ThenByDescending:用于后续的排序条件。
示例:先按年龄升序,再按分数降序,最后按姓名升序
using System.Linq;
// 1. 年龄升序 (Age ASC)
// 2. 如果年龄相同,按分数降序 (Score DESC)
// 3. 如果分数也相同,按姓名升序 (Name ASC)
var sortedStudents = students
.OrderBy(s => s.Age) // 第一条件:年龄升序
.ThenByDescending(s => s.Score)// 第二条件:分数降序
.ThenBy(s => s.Name) // 第三条件:姓名升序
.ToList(); // 注意:必须调用 ToList() 才执行排序并生成新列表
foreach (var s in sortedStudents)
{
Console.WriteLine($"Name: {s.Name}, Age: {s.Age}, Score: {s.Score}");
}
优点:
- 代码清晰,逻辑一目了然。
- 支持任意数量的排序条件。
- 不修改原始集合。
缺点:
- 会创建新的列表对象,内存开销稍大。
- 对于超大集合(百万级),性能略低于
Sort。
方法二:使用 List.Sort + Lambda 表达式
这种方式是原地排序(In-place),直接修改原列表,性能通常更好,适合对性能敏感的场景。
示例:实现同样的多条件排序
// 使用 Comparison<T> 委托
students.Sort((x, y) =>
{
// 1. 比较年龄 (升序)
int ageCompare = x.Age.CompareTo(y.Age);
if (ageCompare != 0)
return ageCompare;
// 2. 年龄相同,比较分数 (降序 -> 注意参数顺序交换或取反)
int scoreCompare = y.Score.CompareTo(x.Score); // y.CompareTo(x) 实现降序
if (scoreCompare != 0)
return scoreCompare;
// 3. 分数相同,比较姓名 (升序)
return x.Name.CompareTo(y.Name);
});
关键点:
CompareTo返回负数表示前者小,正数表示前者大,0 表示相等。- 如果前一个条件不相等(
!= 0),直接返回结果;如果相等,继续比较下一个条件。 - 降序技巧 :使用
y.CompareTo(x)或者-x.CompareTo(y)(注意整数溢出风险,推荐前者)。
方法三:使用 IComparer<T> 接口(适合复杂/复用逻辑)
如果排序逻辑非常复杂,或者需要在多处复用,建议实现 IComparer<T> 接口。
public class StudentComparer : IComparer<Student>
{
public int Compare(Student x, Student y)
{
if (x == null && y == null) return 0;
if (x == null) return -1;
if (y == null) return 1;
// 1. 年龄升序
int result = x.Age.CompareTo(y.Age);
if (result != 0) return result;
// 2. 分数降序
result = y.Score.CompareTo(x.Score);
if (result != 0) return result;
// 3. 姓名升序
return string.Compare(x.Name, y.Name, StringComparison.Ordinal);
}
}
// 使用
students.Sort(new StudentComparer());
方法四:使用 ComparisonChain 风格(第三方库或自定义辅助类)
为了简化 Sort 中的 if-else 嵌套,可以编写一个简单的辅助类或使用类似 Google Guava 的链式比较思想。
// 简单的辅助扩展方法
public static class SortExtensions
{
public static void SortBy<T>(this List<T> list, params Func<T, object>\[\] keySelectors)
{
list.Sort((x, y) =>
{
foreach (var selector in keySelectors)
{
var kx = selector(x);
var ky = selector(y);
// 处理 null
if (kx == null && ky == null) continue;
if (kx == null) return -1;
if (ky == null) return 1;
// 比较
int cmp = Comparer<object>.Default.Compare(kx, ky);
if (cmp != 0) return cmp;
}
return 0;
});
}
}
// 使用 (注意:这种方法默认都是升序,且装箱可能有性能损耗,仅适用于简单场景)
// students.SortBy(s => s.Age, s => -s.Score, s => s.Name);
// 注意:-s.Score 仅适用于数值类型且需手动处理降序逻辑,不如 LINQ 直观
总结与建议
| 特性 | LINQ (OrderBy/ThenBy) |
List.Sort (Lambda) |
IComparer<T> |
|---|---|---|---|
| 可读性 | ⭐⭐⭐⭐⭐ (最佳) | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 性能 | 中等 (创建新列表) | ⭐⭐⭐⭐⭐ (原地排序) | ⭐⭐⭐⭐⭐ (原地排序) |
| 是否修改原列表 | 否 | 是 | 是 |
| 适用场景 | 大多数业务场景,Web API,UI 展示 | 游戏开发,高频循环,大数据量 | 复杂逻辑,需要复用的排序规则 |
**推荐做法:**
- 日常开发 :优先使用 LINQ,代码维护成本最低。
- 高性能要求 (如 Unity 游戏每帧排序、大规模数据处理):使用 **
List.Sort+ Lambda** 或 **IComparer**。
如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。