array.sort 使用 comparison 委托时必须返回 int,不能返回 bool;正确做法是用 compareto、三值比较或 comparer.create,注意 null 处理、溢出、稳定性及引用不变更。

Array.Sort 用 Comparison 排序时,Lambda 表达式必须返回 int
很多人写 Array.Sort(arr, (a, b) => a.Name.CompareTo(b.Name)) 能跑通,但换成 (a, b) => a.Age > b.Age 就出错——因为 Comparison<t></t> 委托要求返回 int,不是 bool。返回 true/false 会编译失败或运行时报 InvalidProgramException(尤其在 .NET Core+JIT 优化后)。
正确做法是显式做三值比较:
Array.Sort(people, (a, b) => {
if (a.Age == b.Age) return 0;
return a.Age a.Age.CompareTo(b.Age)
-
CompareTo是最安全的选择,它天然处理 null、溢出和类型一致性 - 手动减法如
a.Age - b.Age在整数溢出时会返回错误结果(比如int.MaxValue - int.MinValue) - 字符串比较慎用
==或!=判断后再返回 ±1,它不等价于字典序比较
对引用类型数组排序时,Comparison 不会改变原数组元素的引用地址
排序只重排数组中存储的引用(即指针),不会克隆对象、也不会调用任何构造函数或 Clone()。这意味着:
- 排序前后,
arr[0] == originalObject仍为true(引用相等) - 如果排序依据的字段是可变的(如
Person.Age),后续修改该字段会导致数组顺序“失效”,但排序本身不感知 - 若需深拷贝后排序,得先
Array.Clone()或用 LINQ 的.Select(x => new Person { ... }).ToArray()
常见误判场景:排序后修改某个元素的比较字段,再调用 Array.BinarySearch 就可能找不到——因为内部二分查找依赖有序性,而你已破坏它。
Array.Sort 不支持 null 元素参与 IComparable 实现类的默认排序
当调用无参 Array.Sort(arr) 且数组含 null,且元素类型实现了 IComparable(如自定义类),会直接抛 ArgumentNullException:“Value cannot be null.” —— 错误位置在 CompareTo 被调用时传入了 null。
解决方式只有两个:
- 用带
Comparison<t></t>的重载,自己处理null:例如(a, b) => a is null ? (b is null ? 0 : -1) : (b is null ? 1 : a.CompareTo(b)) - 确保数组不含
null,排序前过滤:var nonNull = arr.Where(x => x != null).ToArray(),但注意这会新建数组
注意:.NET 6+ 的 Array.Sort 对 string 等内置类型已内建 null 安全逻辑(null 排最前),但对你自己的类不会自动生效。
升序/降序切换别硬写负号,用 Comparer.Create 更清晰
想把升序改成降序,别写 (a, b) => -(a.Value.CompareTo(b.Value))——负号在 int.MinValue 时翻转失败(-(-2147483648) 还是 -2147483648)。
推荐用 Comparer<t>.Create</t> 配合 Reverse:
Array.Sort(numbers, Comparer<int>.Create((x, y) => y.CompareTo(x))); // 或复用已有比较器 Array.Sort(strings, StringComparer.OrdinalIgnoreCase); Array.Sort(strings, StringComparer.Ordinal.Reverse()); </int>
-
StringComparer系列类型自带Reverse()方法,语义明确且无溢出风险 - 自定义类型建议实现
IComparer<t></t>而非只靠IComparable<t></t>,便于复用和测试 - 性能上,
Comparer<t>.Create</t>是委托缓存的,比每次 new 匿名方法略优
真正容易被忽略的是:排序稳定性。C# 的 Array.Sort 是**不稳定排序**(相同键值的元素相对顺序可能改变),如果业务依赖原始顺序(比如分页后合并),得自己加索引字段或改用 OrderBy(它是稳定排序,但会分配新数组)。











