c# - 由于整数溢出,OrderByDescending 操作不正确

标签 c# linq sorting .net-4.6.1

在浏览 Enumerable 类的 .Net Framework 源代码时,我发现它的内部 EnumerableSorter 类 CompareKeys method用于排序的有以下一行:

return descending ? -c : c;

其中 cIComparer.Compare Method (T, T) 的结果方法调用,这实际上并不强制我们仅使用 -1、1 或 0 来表示排序。

考虑到 -Int32.MinValue == Int32.MinValue由于整数溢出,它可能导致不正确的排序,如以下代码片段所示:

public class Value : IComparable<Value>
{
    private readonly Int32 _value;
    public Value(Int32 value)
    {
        this._value = value;
    }

    public Int32 CompareTo(Value other)
    {
        if (other == null)
            throw new ArgumentNullException(nameof(other));
        var cmp = this._value.CompareTo(other._value);
        if (cmp > 0)
            return Int32.MaxValue;
        if (cmp < 0)
            return Int32.MinValue;
        return 0;
    }

    public override String ToString()
    {
        return this._value.ToString();
    }
}

private static void Print<T>(String header, IEnumerable<T> values)
{
    Console.WriteLine(header);
    foreach (var item in values)
    {
        Console.WriteLine(item);
    }
    Console.WriteLine();
}

public static void Main()
{
    try
    {
        var notSorted = new[] { 1, 3, 2 }
            .Select(i => 
                new Value(i))
            .ToArray();

        Print("Not sorted", notSorted);
        Print("Sorted by", notSorted.OrderBy(item => item));
        Print("Sorted by descending", notSorted.OrderByDescending(item => item));
    }
    catch (Exception exc)
    {
        Console.WriteLine(exc);
    }
    Console.WriteLine("Press any key...");
    Console.ReadKey(true);         
}

对于 OrderByDescending 它产生:

Sorted by descending
3
1
2

这是预料之中的,但也是一个明显不正确的结果。

所以这似乎是 .Net 中的一个缺陷,但如果 CompareTo 以合理的方式实现则不太可能发生。我说得对吗?

更新:

正如 SLaks 所指出的这个问题早已为人所知,但尽管发布了所有新版本,但仍未得到解决 - https://connect.microsoft.com/VisualStudio/feedback/details/634949/orderbydescending-fails-in-linq-to-objects-when-a-comparer-returns-int-minvalue

正如 usr 所指出的.Net Core 已修复此问题 - https://github.com/dotnet/corefx/blob/35e03c78d89d02f2d3b4a1f8b277a35c88f45750/src/System.Linq/src/System/Linq/OrderedEnumerable.cs#L628

最佳答案

似乎没有多少答案可以做出,所以:

正如 SLaks 所指出的,该问题早已为人所知,但从未在 .NET Framework 中得到修复,尽管有所有新版本(截至目前为 .Net 4.6.1)- https://connect.microsoft.com/VisualStudio/feedback/details/634949/orderbydescending-fails-in-linq-to-objects-when-a-comparer-returns-int-minvalue .

避免此问题的唯一方法是不从 CompareTo 实现中返回 Int32.MinValue


但正如 usr 所指出的那样 .Net Core 已修复此问题 - https://github.com/dotnet/corefx/blob/35e03c78d89d02f2d3b4a1f8b277a35c88f45750/src/System.Linq/src/System/Linq/OrderedEnumerable.cs#L628

关于c# - 由于整数溢出,OrderByDescending 操作不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35537357/

相关文章:

c# - C#-mscorlib.dll中未处理的异常

c# - 保存文件对话框,限制名称

c# - 为什么我们不能使用 expression-bodied 构造函数?

c# - 内联 LINQ 查询创建委托(delegate)实例的效率?

python - 如何在 python 中的条件下对列表进行排序?

c# - Func<Owned<T>> 与 Func<T> 依赖关系

c# - Linq 获取句子中的单词

c# - 用 LINQ 合并两个 IEnumerable

python - Python 中的 QuickSort - 程序挂起较大的输入大小?

jquery - 使用 jQuery DataTables 自定义排序持续时间