.NET 3.5和.NET 4.0之间排序的区别

9
我遇到了一个非常奇怪的.NET框架行为,即在对集合进行排序时。 这种行为在.NET 3.5和4.0之间有所不同(但我认为我知道原因),但更重要的是(这是我的真正关注点),不同机器上相同框架的行为也不同

背景

我正在开发一款软件,该软件依赖于第三方软件(spring.net),在某些情况下,它会对一个所有项都“相等”的集合进行排序(比较器始终返回0)。这不在我的控制范围内,如果该列表的排序行为始终保持一致,我将非常满意。但事实并非如此。

如何复现

创建一个简单的项目,在.NET 3.5中运行下面的代码。 当编译为3.5时,行为似乎是一致的,集合将被“反转”(结果为Three, Two, One)。 现在,请将项目目标更改为.NET 4 (不是4.5),然后再次运行: 在我的机器上,它不再反转集合(One, Two, Three),但在其他同事的机器上,它确实反转了(Three, Two, One)!!!我们的设置完全一样...

请告诉我,在您的机器上,在4.0下是哪一个?反转还是不反转?

我正在尝试评估我的设置是否正确。

概念证明

class Program
{
    static void Main()
    {
        var collection = new ArrayList
        {
            "One",
            "Two",
            "Three",
        };

        // It should in any case write One, Two, Three
        Console.Out.WriteLine("Before sort: ");
        foreach (string item in collection)
        {
            Console.Out.WriteLine("\t"+item);
        }

        collection.Sort(new OrderComparator());

        // In .NET 3.5, it will write Three, Two, One
        // In .NET 4, it will sometimes write Three, Two, One, sometimes One, Two, Three: what is it for you?
        Console.Out.WriteLine("After sort: ");
        foreach (string item in collection)
        {
            Console.Out.WriteLine("\t" + item);
        }

        Console.Out.WriteLine("--end--");
        Console.Read();
    }
}

public class OrderComparator : IComparer
{
    public virtual int Compare(object o1, object o2)
    {
        return 0;
    }
}

另外,如果您知道为什么会出现这种情况,请告诉我!


2
就像他所说的那样,排序是在无法更改的第三方代码中完成的。 - DOK
提示:LINQ的排序是“稳定”的,但不是原地排序。 - Marc Gravell
1
MSDN明确指出Array.Sort(以及使用它的所有内容)是不稳定的。那么你在这里想要实现什么?如果您无法控制排序,并且文档说不能保证...显然,您不应该依赖顺序。(副注:LINQ的OrderBy提供了稳定的排序。) - Eli Arbel
.NET 4 中的排序算法已更改。这是一个 GIGO 问题,垃圾进,垃圾出。请编写一个适当的比较器。 - Hans Passant
就像我之前所说的,问题在于我无法控制任何排序等操作。这基本上是Spring.net中的一个错误,在3.5版本下(幸运地)没有引起任何问题,但在切换到4.0版本后开始给我们带来了麻烦。最好的解决方法似乎是修复Spring.net... - Antoine Jaussoin
实际上,我要修改我的先前评论,这个错误不在Spring.net中(即使Spring.net应该抱怨),而是在我们的一个配置文件中,我们没有设置Order属性。无论如何,问题已经解决 :) - Antoine Jaussoin
1个回答

9
ArrayList.Sort()排序不稳定,因此您无法预测“相同”项目排序的顺序。
此外,由于ArrayList.Sort()可能使用随机机制选择其QuickSort算法的中心轴,因此相同的项目在不同PC甚至同一PC上可能排序不同。
[编辑:我找不到任何证据表明当前实现会选择随机中心轴,但数组排序仍然不稳定。我猜测随机性来自于TrySZSort()中的本地代码QuickSort实现,这可能是被调用的内容。]
出于兴趣,反射器显示了ArrayList.Sort()中的此代码(如果您深入挖掘):
internal void Sort(int left, int length)
{
    if (BinaryCompatibility.TargetsAtLeast_Desktop_V4_5)
    {
        this.IntrospectiveSort(left, length);
    }
    else
    {
        this.DepthLimitedQuickSort(left, (length + left) - 0x1, 0x20);
    }
}

这似乎是在为.NET 4.5选择完全不同的排序算法。


可能就是这样:看起来我们机器的区别在于我有VS 2012,而其他用户没有(只有2010)。显然安装VS 2012会替换掉一些.NET 4的DLL,并且可能会像您之前提到的那样改变排序算法为内省软件。谢谢! - Antoine Jaussoin
谢谢您添加了反射代码,展示了IntrospectiveSort与DepthLimitedQuickSort之间的区别。这对我帮助很大。 - cplotts

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接