List.Sort异常:IComparer.Compare()返回不一致结果,求排查原因
执行List排序时触发如下错误:
Unable to sort because the IComparer.Compare() method returns inconsistent results. Either a value does not compare equal to itself, or one value repeatedly compared to another value yields different results.
堆栈跟踪
Message: Unable to sort because the IComparer.Compare() method returns inconsistent results. Either a value does not compare equal to itself, or one value repeatedly compared to another value yields different results. IComparer: 'Premise.PremiseLIVE.CommGateway.Workflows.Sequential.SequentialWorkflowData.TransportJobPriorityDataSort'. StackTrace: at System.Collections.Generic.IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(Object comparer) at System.Collections.Generic.ArraySortHelper`1.Sort(T[] keys, Int32 index, Int32 length, IComparer`1 comparer) at System.Array.Sort[T](T[] array, Int32 index, Int32 length, IComparer`1 comparer) at System.Collections.Generic.List`1.Sort(Int32 index, Int32 count, IComparer`1 comparer) at Premise.PremiseLIVE.CommGateway.Workflows.Sequential.WorkflowActivities.wcSortTransportJobs.ExecuteSequential(ActivityExecutionContext executionContext) Source: mscorlib TargetSite: Void ThrowOrIgnoreBadComparer(System.Object)"
核心原因分析
从提供的TransportJobPriorityDataSort类的Compare方法代码来看,存在以下破坏比较器一致性的问题:
1. Pickup时间比较逻辑错误
在最后比较TransportPickupTime的代码段中,两次判断条件完全重复:
if ( x.TransportPickupTime < y.TransportPickupTime ) { return ( _xGTy ); } if ( x.TransportPickupTime < y.TransportPickupTime ) { return ( _xLTy ); }
第二个判断应该为x.TransportPickupTime > y.TransportPickupTime,否则当x.TransportPickupTime大于y.TransportPickupTime时,两个条件都不满足,直接返回_xEQy(0)。这会导致:
Compare(x, y)返回0,但Compare(y, x)会因y.TransportPickupTime < x.TransportPickupTime返回_xGTy,两者结果不互为相反数,违反比较器的对称性要求;- 重复比较同一对元素时得到矛盾结果,触发排序报错。
2. 未处理Nullable类型的Null值
代码直接调用x.TransportPickupTime.Value和y.TransportPickupTime.Value,若TransportPickupTime是Nullable<DateTime>且值为null,会抛出InvalidOperationException,但异常被空catch块捕获后直接返回0。这会导致:
- 时间为null的元素与其他任何元素比较都返回0,破坏比较器的传递性规则,排序逻辑彻底混乱。
3. 集合索引访问可能抛出异常
_orgTransportTyps[x.JobTransportType]和_orgTransportTyps[y.JobTransportType]的索引访问,若JobTransportType不存在于集合中,会抛出KeyNotFoundException,同样被空catch块吞掉并返回0。这会将原本有排序差异的元素判定为相等,破坏比较结果的一致性。
4. 空catch块隐藏异常
整个Compare方法的逻辑被包裹在空catch块中,任何异常都会被忽略并返回0,这完全违背了IComparer<T>的契约要求——比较器必须稳定、一致,不能随意返回默认值掩盖错误。
修复建议
- 修正pickup时间的比较逻辑,将第二个判断条件改为
x.TransportPickupTime > y.TransportPickupTime; - 提前判断
TransportPickupTime是否为null,明确指定null值的排序规则(比如排在最前或最后); - 索引访问
_orgTransportTyps前,先检查JobTransportType是否存在,避免抛出异常; - 移除空catch块,或在catch中记录日志并抛出合理异常,禁止随意返回0。
内容的提问来源于stack exchange,提问作者TVicky

