C# 对某些为空的IComparable对象进行排序
大多数人在编写实现IComparable的引用类型(类)时,使用null小于任何实际对象的约定。但是如果你尝试使用相反的惯例,会发生一些有趣的事情:C# 对某些为空的IComparable对象进行排序,c#,.net,null,icomparable,C#,.net,Null,Icomparable,大多数人在编写实现IComparable的引用类型(类)时,使用null小于任何实际对象的约定。但是如果你尝试使用相反的惯例,会发生一些有趣的事情: using System; using System.Collections.Generic; namespace SortingNulls { internal class Child : IComparable<Child> { public int Age; public string Name;
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");
}
}
}
使用系统;
使用System.Collections.Generic;
命名空间排序空
{
内部类子级:IComparable
{
公共信息;
公共字符串名称;
公共整数比较(其他子项)
{
如果(其他==null)
return-1;//你有什么问题?
返回此.Age.CompareTo(其他.Age);
}
公共重写字符串ToString()
{
返回string.Format(“{0}({1}年)”,this.Name,this.Age);
}
}
内部静态类程序
{
私有静态void Main()
{
var listOfChilds=新列表
{
无效的
无效的
无效的
无效的
新孩子{Age=5,Name=“Joe”},
新孩子{Age=6,Name=“Sam”},
新孩子{Age=3,Name=“Jude”},
新孩子{Age=7,Name=“Mary”},
无效的
无效的
无效的
无效的
新孩子{Age=7,Name=“Pete”},
无效的
新孩子{Age=3,Name=“Bob”},
新孩子{Age=4,Name=“Tim”},
无效的
无效的
};
listOfChilds.Sort();
WriteLine(“排序列表从这里开始”);
for(int i=0;i
运行上述代码时,您会看到空引用没有按预期排序。显然,在比较A和B时,如果A是对象,B为空,则使用用户定义的比较,但如果相反,A为空,B为对象,则使用某些BCL比较
这是一个bug吗?不,这不是bug。实现
IComparable
的CompareTo
方法在子类上定义。换句话说,如果为了进行比较而必须调用某个类型上的方法
如果要比较的子项
中有一项为空,如何对其调用CompareTo
请注意,根据以下定义:
根据定义,任何对象的比较大于(或遵循)一个空引用(在Visual Basic中为零),而两个空引用的比较相等
这解释了你观察到的结果
解决方案是委托给其他类来执行比较。查看界面。如果您尝试评估this.Age.CompareTo(other.Age)),将会发生什么代码>如果此
为空
?事实上,这个
在C#中永远不可能是null
至于询问它是否是bug,请参见。类型T
的默认比较器必须考虑第一个元素(我们称之为a)为null
的场景。假设它看起来像这样:
if (ReferenceEquals(a, null))
{
return -1;
}
return a.CompareTo(b);
这是基于:
此方法使用默认比较器
比较器(属于T)。T类型的默认值为
确定列表元素的顺序
可以说,如果两个元素都为null
,则最上面的步骤只能返回0
,否则使用b的相反项
不过,我不会真的把它叫做虫子。这只是需要注意的一点。不,您的代码有一个“bug”,因为它没有遵循定义i可比较的标准。CompareTo()
:
具体来说:根据定义,任何对象的比较大于(或遵循)null
,两个null
引用的比较相等。
在您的示例中,您将对象定义为比较小于(或先于)null
,这与应该执行的操作正好相反。回答得很好。我没有注意到文档中说对象的比较必须大于null。当A为null且B不为null时,框架可以交换A和B,调用我的方法,然后翻转返回的Int32的符号。我认为这有时会发生在旧的非通用的IComparable上。当然,对于IComparer或Comparison委托,很容易将null作为第一个参数处理。