在C#中对List集合实现多属性排序的四种方法

 更新时间:2026年06月08日 09:19:04   作者:hefeng_aspnet  
这篇文章主要介绍了在C#中对List集合实现多属性排序的四种方法:使用 LINQ、使用 List.Sort + Lambda 表达式、使用 IComparer 接口以及使用 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‌。

到此这篇关于在C#中对List集合实现多属性排序的四种方法的文章就介绍到这了,更多相关C# List集合多属性排序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C#使用foreach语句遍历队列(Queue)的方法

    C#使用foreach语句遍历队列(Queue)的方法

    这篇文章主要介绍了C#使用foreach语句遍历队列(Queue)的方法,涉及foreach语句的使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-04-04
  • Unity实现简单手势识别

    Unity实现简单手势识别

    这篇文章主要为大家详细介绍了Unity实现简单手势识别,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-07-07
  • C#以太网Sockets服务器设计实现

    C#以太网Sockets服务器设计实现

    本文主要介绍了C#以太网Sockets服务器设计实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • C#数字图像处理之图像二值化(彩色变黑白)的方法

    C#数字图像处理之图像二值化(彩色变黑白)的方法

    这篇文章主要介绍了C#数字图像处理之图像二值化(彩色变黑白)的方法,可实现图像从彩色转变为黑白的效果,非常具有实用价值,需要的朋友可以参考下
    2015-04-04
  • C#访问SQL Server数据库的实现方法

    C#访问SQL Server数据库的实现方法

    这篇文章主要介绍了C#访问SQL Server数据库的实现方法,以实例形式简单分析了C#连接、查询SQL Server数据库的具体技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-10-10
  • C#结合JS解决Word添加无效位图导致进程停滞的问题

    C#结合JS解决Word添加无效位图导致进程停滞的问题

    这篇文章主要为大家详细介绍了C#如何结合JS解决Word添加无效位图导致进程停滞的问题,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-11-11
  • C#实现将音频PCM数据封装成wav文件

    C#实现将音频PCM数据封装成wav文件

    这篇文章主要为大家详细介绍了C#如何实现将音频PCM数据封装成wav文件,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2023-10-10
  • C# 中 System.Index 结构体和 Hat 运算符(^)的使用示例

    C# 中 System.Index 结构体和 Hat 运算符(^)的使用示例

    这篇文章主要介绍了C# 中 System.Index 结构体和 Hat 运算符(^)的使用示例,帮助大家更好的理解和使用C#,感兴趣的朋友可以了解下
    2020-09-09
  • XAML如何获取元素的位置

    XAML如何获取元素的位置

    这篇文章主要为大家详细介绍了XAML如何获取元素的位置,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06
  • C#窗口实现定时关机系统

    C#窗口实现定时关机系统

    这篇文章主要为大家详细介绍了C#窗口实现定时关机系统,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-07-07

最新评论