C# 如何在LINQ中始终为空的情况下进行自定义排序?
我需要在内存中按升序或降序排列字符串或数字列表。但是,列表可以包含空值,并且所有空值必须出现在数字或字符串之后 也就是说,输入数据可能是: 1, 100, null, 5, 32.3 1100,空,532.3 上升的结果将是 1, 5, 32.3, 100, null 100, 32.3, 5, 1, null 1,5,32.3100,空 降序名单是 1, 5, 32.3, 100, null 100, 32.3, 5, 1, null 100,32.3,5,1,nullC# 如何在LINQ中始终为空的情况下进行自定义排序?,c#,linq,C#,Linq,我需要在内存中按升序或降序排列字符串或数字列表。但是,列表可以包含空值,并且所有空值必须出现在数字或字符串之后 也就是说,输入数据可能是: 1, 100, null, 5, 32.3 1100,空,532.3 上升的结果将是 1, 5, 32.3, 100, null 100, 32.3, 5, 1, null 1,5,32.3100,空 降序名单是 1, 5, 32.3, 100, null 100, 32.3, 5, 1, null 100,32.3,5,1,null 关于如何使其工作,您有
关于如何使其工作,您有什么想法吗?您可以编写自己的比较器,将非空比较器委托给现有比较器,但总是在最后对空比较器进行排序。大概是这样的:
public class NullsLastComparer<T> : IComparer<T>
{
private readonly IComparer<T> proxy;
public NullsLastComparer(IComparer<T> proxy)
{
this.proxy = proxy;
}
public override int Compare(T first, T second)
{
if (first == null && second == null)
{
return 0;
}
if (first == null)
{
return 1;
}
if (second == null)
{
return -1;
}
return proxy.Compare(first, second);
}
}
公共类NullsLastComparer:IComparer
{
专用只读IComparer代理;
公共NullsLastComparer(IComparer代理)
{
this.proxy=代理;
}
公共覆盖整数比较(T第一,T第二)
{
if(first==null&&second==null)
{
返回0;
}
if(first==null)
{
返回1;
}
if(秒==null)
{
返回-1;
}
返回proxy.Compare(第一,第二);
}
}
编辑:此方法的几个问题:
首先,它不能很好地处理匿名类型;您可能需要一个单独的扩展方法才能很好地工作。或者使用肯的答案:)
更重要的是,它违反了IComparer
契约,该契约规定空值应该是第一位的。现在我个人认为这是IComparer
规范中的一个错误-它可能应该定义比较器应该处理空值,但不应该指定它们是第一个还是最后一个。。。它使得这样的需求(这是完全合理的)不可能像我们希望的那样干净地实现,并且对于像反向比较器这样的东西有各种各样的尴尬的后果。您可能希望这样的事情完全颠倒顺序,但根据规范,它在开始时仍应保持空值:(
我不认为我见过任何.NET排序实现实际上依赖于此,但它确实值得注意。我面前没有编译器可供检查,但我想:
x.OrderBy(i => i == null).ThenBy(i => i)
正如Jon所说,您需要定义自定义比较器,实现
IComparer
。下面是自定义比较器中的Compare
方法如何在最后保持null
public int Compare(Object x, Object y)
{
int retVal = 0;
IComparable valX = x as IComparable;
IComparable valY = y as IComparable;
if (valX == null && valY == null)
{
return 0;
}
if (valX == null)
{
return 1;
}
else if (valY == null)
{
return -1;
}
return valX.CompareTo(valY);
}
这不是违反了与.NET排序实现的合同吗?我想我已经在某个地方读到排序方法可以假定null是第一位的…或者…?@Lasse:这违反了
IComparer
接口,是的-我将编辑我的帖子来提及这一点。是的,但从我读到这篇文章时的记忆来看,听起来像是由于这个契约,排序方法可能会走捷径,因此在某些情况下实际上不会调用比较方法,因为它“知道”结果会是什么。换句话说,在某些情况下,这不会产生奇怪的结果吗?@Lasse:我不能说我见过任何走捷径的方法就像那样…这意味着更多的工作,而不是更少的工作,因为它不会像一般那样对待它。如果你有任何示例,我很想看看它们。不需要输入I可比较的
?并且构造函数应该被定义为公共NullsLastComparer(I比较代理)
没有T.Nice…这是一个非常好的方法。如果可以的话,我会不止一次地投票支持这个方法…非常好。这个方法也适用于Linq To实体,并且可以正确地转换为Sql。尽管它是如此简单的解决方案,但对我来说它看起来非常聪明…我正在编写一个自定义比较器。。。