如何在C# CompareTo方法中妥善处理NULL属性?
问题
我需要比较两个AdminEngineTableRowModel类的实例是否相等,编写的CompareTo方法存在缺陷:当NXSTDT等属性为NULL时,调用CompareTo会引发错误。我尝试过通过构造函数初始化所有属性,或在方法中逐个判断属性非空,但认为这类写法不够优雅,请问是否有更优的实现方式?
存在问题的代码:
public int CompareTo(AdminEngineTableRowModel other) { int result; if (other != null) { result = NXSTDT.CompareTo(other.NXSTDT); if (result == 0) result = DALOC.CompareTo(other.DALOC); if (result == 0) result = DealerID.CompareTo(other.DealerID); if (result == 0) result = Status.CompareTo(other.Status); if (result == 0) result = OrderNumber.CompareTo(other.OrderNumber); if (result == 0) result = Dealership.CompareTo(other.Dealership); if (result == 0) result = Serial.CompareTo(other.Serial); if (result == 0) result = Model.CompareTo(other.Model); if (result == 0) result = OrderDate.CompareTo(other.OrderDate); if (result == 0) result = StartDate.CompareTo(other.StartDate); if (result == 0) result = Confirmed.CompareTo(other.Confirmed); if (result == 0) result = Deposit.CompareTo(other.Deposit); if (result == 0) result = Engine.CompareTo(other.Engine); if (result == 0) result = Color.CompareTo(other.Color); if (result == 0) result = Name.CompareTo(other.Name); } else { result = 1; } return result; }
问题出在属性为NULL时,例如:
result = NULL.CompareTo(other.NXSTDT); // 这会引发错误
我曾尝试的改进写法:
public int CompareTo(AdminEngineTableRowModel other) { int result; if (other != null) { if ((NXSTDT == null) && (other.NXSTDT != null)) result = 1; if (result == 0) result = NXSTDT.CompareTo(other.NXSTDT); if ((DALOC == null) && (other.DALOC != null)) result = 1; if (result == 0) result = DALOC.CompareTo(other.DALOC); // {snip} } else { result = 1; } return result; }
但我认为这种写法不够规范,希望找到更好的解决办法。
更优雅的实现方案
方法1:使用Comparer<T>.Default处理null比较
.NET内置的Comparer<T>.Default已经原生处理了null的比较逻辑:null会被视为小于任何非null值,两个null相等。直接用它替代手动调用CompareTo,代码会简洁很多,且无需额外的null判断。
完整实现(替换[属性类型]为对应属性的实际类型,比如字符串用string、可空日期用DateTime?):
public int CompareTo(AdminEngineTableRowModel other) { if (other == null) return 1; int result = Comparer<string>.Default.Compare(NXSTDT, other.NXSTDT); if (result != 0) return result; result = Comparer<string>.Default.Compare(DALOC, other.DALOC); if (result != 0) return result; result = Comparer<string>.Default.Compare(DealerID, other.DealerID); if (result != 0) return result; result = Comparer<string>.Default.Compare(Status, other.Status); if (result != 0) return result; result = Comparer<string>.Default.Compare(OrderNumber, other.OrderNumber); if (result != 0) return result; result = Comparer<string>.Default.Compare(Dealership, other.Dealership); if (result != 0) return result; result = Comparer<string>.Default.Compare(Serial, other.Serial); if (result != 0) return result; result = Comparer<string>.Default.Compare(Model, other.Model); if (result != 0) return result; result = Comparer<DateTime?>.Default.Compare(OrderDate, other.OrderDate); if (result != 0) return result; result = Comparer<DateTime?>.Default.Compare(StartDate, other.StartDate); if (result != 0) return result; result = Comparer<bool?>.Default.Compare(Confirmed, other.Confirmed); if (result != 0) return result; result = Comparer<decimal?>.Default.Compare(Deposit, other.Deposit); if (result != 0) return result; result = Comparer<string>.Default.Compare(Engine, other.Engine); if (result != 0) return result; result = Comparer<string>.Default.Compare(Color, other.Color); if (result != 0) return result; return Comparer<string>.Default.Compare(Name, other.Name); }
方法2:封装通用null安全比较方法
如果需要自定义null的比较规则(比如把null视为大于非null值),可以封装一个通用方法复用,避免重复代码:
private int NullSafeCompare<T>(T a, T b) where T : IComparable<T> { if (a == null && b == null) return 0; if (a == null) return 1; // 自定义规则:null大于非null,若要相反则返回-1 return a.CompareTo(b); }
然后在CompareTo中调用:
public int CompareTo(AdminEngineTableRowModel other) { if (other == null) return 1; int result = NullSafeCompare(NXSTDT, other.NXSTDT); if (result != 0) return result; result = NullSafeCompare(DALOC, other.DALOC); if (result != 0) return result; // 后续属性依次类推... return NullSafeCompare(Name, other.Name); }
方法3:LINQ链式比较(C# 6+)
利用LINQ的FirstOrDefault方法,可以将所有属性的比较结果放入数组,直接取第一个非0的结果作为最终返回值,代码紧凑且逻辑清晰:
public int CompareTo(AdminEngineTableRowModel other) { if (other == null) return 1; return new[] { Comparer<string>.Default.Compare(NXSTDT, other.NXSTDT), Comparer<string>.Default.Compare(DALOC, other.DALOC), Comparer<string>.Default.Compare(DealerID, other.DealerID), Comparer<string>.Default.Compare(Status, other.Status), Comparer<string>.Default.Compare(OrderNumber, other.OrderNumber), Comparer<string>.Default.Compare(Dealership, other.Dealership), Comparer<string>.Default.Compare(Serial, other.Serial), Comparer<string>.Default.Compare(Model, other.Model), Comparer<DateTime?>.Default.Compare(OrderDate, other.OrderDate), Comparer<DateTime?>.Default.Compare(StartDate, other.StartDate), Comparer<bool?>.Default.Compare(Confirmed, other.Confirmed), Comparer<decimal?>.Default.Compare(Deposit, other.Deposit), Comparer<string>.Default.Compare(Engine, other.Engine), Comparer<string>.Default.Compare(Color, other.Color), Comparer<string>.Default.Compare(Name, other.Name) }.FirstOrDefault(r => r != 0); }
内容的提问来源于stack exchange,提问作者user153923
相关产品推荐
相关产品推荐

