大多数人在编写实现IComparable< T>的refence类型(类)时,使用null比任何实际对象少的约定。但是如果你试图使用相反的约定,就会发生一些有趣的事情:
using System;
using System.Collections.Generic;
namespace SortingNulls
{
internal class Child : IComparable<Child>
{
public int Age;
public string Name;
public int CompareTo(Child other)
{
if (other == null)
return -1; // what's your problem?
return this.Age.CompareTo(other.Age);
}
public override string ToString()
{
return string.Format("{0} ({1} years)", this.Name, this.Age);
}
}
internal static class Program
{
private static void Main()
{
var listOfChilds = new List<Child>
{
null,
null,
null,
null,
new Child { Age = 5, Name = "Joe" },
new Child { Age = 6, Name = "Sam" },
new Child { Age = 3, Name = "Jude" },
new Child { Age = 7, Name = "Mary" },
null,
null,
null,
null,
new Child { Age = 7, Name = "Pete" },
null,
new Child { Age = 3, Name = "Bob" },
new Child { Age = 4, Name = "Tim" },
null,
null,
};
listOfChilds.Sort();
Console.WriteLine("Sorted list begins here");
for (int i = 0; i < listOfChilds.Count; ++i)
Console.WriteLine("{0,2}: {1}", i, listOfChilds[i]);
Console.WriteLine("Sorted list ends here");
}
}
}
运行上面的代码时,您会看到空引用未按预期排序。显然,当比较A和B时,如果A是对象而B是null,则使用用户定义的比较,但如果相反A为空且B是对象,则使用某些BCL比较。
这是一个错误吗?
答案 0 :(得分:8)
不,这不是错误。实施CompareTo
的{{1}}方法已在IComparable<Child>
课程中定义。换句话说,如果你必须在你的一个类型上调用一个方法来进行比较。
如果要比较的Child
项之一为空,您如何在其上调用Child
?
请注意IComparable的定义:
“根据定义,任何对象都比空(或跟随)空引用(在Visual Basic中为Nothing),并且两个空引用相互比较相等。”
这解释了您观察到的结果。
解决方案是委托其他一些类来执行比较。请参阅IComparer界面。
答案 1 :(得分:1)
如果this.Age.CompareTo(other.Age);
this
为null
,您试图评估this
会发生什么?实际上,null
在C#中永远不会是{{1}}。
至于询问是否是错误,请参阅this blog post。
答案 2 :(得分:1)
类型Comparer<T>
的默认T
必须考虑第一个元素(我们称之为A)为null
的情况。让我们说它看起来像这样:
if (ReferenceEquals(a, null))
{
return -1;
}
return a.CompareTo(b);
这基于the documentation of List<T>.Sort
:
此方法使用默认比较器 类型T到
Comparer(Of T).Default
确定列表元素的顺序。
可以说,如果两个元素都是0
,那么最上一步只能返回null
,否则请使用b.CompareTo(a)
的反面。
我不会把它称为 bug 。这只是需要注意的事情。
答案 3 :(得分:1)
不,它的代码有“错误”,因为它没有遵循定义IComparable.CompareTo()
的标准:IComparable
具体来说:根据定义,任何对象都会比较大于(或跟随)null
,并且两个null
引用相互比较相等。
在您的示例中,您定义的对象要比null
小于(或先于){},这恰好与应该如何进行比较。