简体   繁体   English

列表的行为 <T> .NET 4.5中的排序从.NET 4.0改变了吗?

[英]Behaviour of List<T>.Sort in .NET 4.5 changed from .NET 4.0?

I have the following test inside a project targeting .NET 4.0: 我在针对.NET 4.0的项目中进行了以下测试:

[TestFixture]
public class Donkey
{
    [Test]
    public void TestListSorting()
    {
        var expected = new[]
                    {
                                MockRepository.GenerateStub<IComparable>(),
                                MockRepository.GenerateStub<IComparable>()
                    };

        var sorted = new List<IComparable>(expected);

        CollectionAssert.AreEqual(expected, sorted);
        sorted.Sort();
        CollectionAssert.AreEqual(expected, sorted);

    }
}

If I run it on a machine with only .NET 4.0 installed, it fails. 如果我在仅安装了.NET 4.0的计算机上运行它,则会失败。 If I run it on a machine with only .NET 4.5 installed, it passes. 如果我在只安装了.NET 4.5的机器上运行它,它会通过。

I am assuming that in .NET 4.5 the implementation of Sort has been changed to maintain order when sorting a list of objects which each return 0 from CompareTo . 我假设在.NET 4.5中, Sort的实现已经改变,以便在排序每个从CompareTo返回0的对象列表时保持顺序。

Now, put aside the obvious insanity of this test. 现在,抛开这个测试的明显疯狂。 I know it's crazy to rely on this kind of behaviour. 我知道依靠这种行为是很疯狂的。

Surely this is a breaking change? 当然这是一个突破性的变化? It is not listed on this page about compatibility between .NET 4.0 and 4.5. 本页未列出.NET 4.0和4.5之间的兼容性。

Is there a reason for this? 是否有一个原因? Am I missing something? 我错过了什么吗? Is there another page which shows actual breaking changes? 是否有其他页面显示实际的重大变化? Should I just have a sit down and stop panicking? 我应该坐下来停止恐慌吗?

I've answered a similar question to this before. 我以前也回答过类似的问题 The sorting method has changed between 4.5 and 4.0, from a quick sort to an introspective sort . 排序方法已在4.5到4.0之间变化,从快速排序到内省排序

It's actually faster, but still it is not a stable sort 1 , that is, one that has the same output for every execution by preserving the order of equal items. 它实际上更快,但它仍然不是一个稳定的排序1 ,也就是说,通过保留相等项的顺序,每次执行具有相同的输出。 Since no implementation of List.Sort is a stable sort, I don't think you've run your unit test above enough times to have it error in both runtimes? 由于没有List.Sort实现是一个稳定的排序,我不认为你已经在上面运行你的单元测试足够的时间让它在两个运行时都出错?

I tried to reproduce it myself with equivalent code and a comparer that returns 0. Sometimes the list order is preserved and sometimes it is not, in both .NET 4.5 and .NET 3.5. 我尝试用等效的代码和一个返回0的比较器自己重现它。有时候,在.NET 4.5和.NET 3.5中,列表顺序都被保留,有时则不然。

Even if it did change the sort type from stable to unstable, its not a breaking change . 即使它确实将排序类型从稳定变为不稳定, 它也不是一个突破性的变化 The type of sort used and the exact output is not part of the contract for List.Sort . 使用的排序类型和确切的输出不是List.Sort合同的List.Sort All that the method contract guarantees is that your items will be in sorted order according to the comparer used. 方法合同保证的所有内容都是根据所使用的比较器,您的项目将按排序顺序排列。

It is interesting, though, because the [MSDN documentation](http://msdn.microsoft.com/en-us/library/b0zbh7b6.aspx) still says it uses QuickSort (via `Array.Sort`), but this is not the case if you were to step through the .NET reference source. 但有趣的是,因为[MSDN文档](http://msdn.microsoft.com/en-us/library/b0zbh7b6.aspx)仍然说它使用QuickSort(通过`Array.Sort`),但这是如果您要逐步浏览.NET参考源,则不然。

1 By definition of using a mix of QuickSort and HeapSort , it should be an unstable sort. 1 使用的混合的定义QuickSortHeapSort ,它应该是一个不稳定的排序。 Even David Musser, the designer of the algorithm states in his paper : 算法的设计者David Musser甚至在他的论文中指出:

Introsort, like quicksort, is not stable -- does not preserve the order of equivalent elements -- so there is still a need to have a separate requirement for a stable sorting routine. 像快速排序一样,Introsort不稳定 - 不保留等效元素的顺序 - 因此仍然需要对稳定的排序例程有单独的要求。

The spec for List.Sort says that the sort used is unstable and thus may not preserve the ordering of equal elements; List.Sort 的规范说使用的排序不稳定,因此可能无法保持相等元素的排序; it doesn't specify a particular re-ordering of equal elements, so you can't really call this change a breaking change. 它没有指定相等元素的特定重新排序,因此您无法真正将此更改称为重大更改。

As @Rawling said, have a look at the documentation for Sort() : 正如@Rawling所说,看一下Sort()的文档

This implementation performs an unstable sort; 此实现执行不稳定的排序; that is, if two elements are equal, their order might not be preserved. 也就是说,如果两个元素相等,则可能不会保留它们的顺序。

So, you're trying to test something that is explicitly documented as undefined. 因此,您正在尝试测试明确记录为未定义的内容。 That is not a breaking change. 这不是一个突破性的变化。

I don't see any change. 我没有看到任何变化。 As others already wrote, both versions perform an unstable sort. 正如其他人已经写过的那样,两个版本执行不稳定的排 Which means that you cannot rely on order of elements that compare as equals. 这意味着您不能依赖于等于比较的元素的顺序。 Their order may or may not change during sort. 他们的订单在排序期间可能会也可能不会改变 It certainly isn't a breaking change. 这肯定不是一个突破性的变化。

See: Documentation of List< T >.Sort 请参阅: List <T> .Sort的文档

From MSDN 来自MSDN

This implementation performs an unstable sort; 此实现执行不稳定的排序; that is, if two elements are equal, their order might not be preserved 也就是说,如果两个元素相等,则可能不会保留它们的顺序

Doesn't look like the order is reliable therefore the test is void. 看起来订单不可靠,因此测试无效。 Also, why are you testing the Sort method anyway? 另外,为什么要测试Sort方法呢? Seems like an unnecessary test to me. 对我来说似乎是一种不必要的考验。

Questions like this often come up with new framework versions. 像这样的问题经常会出现新的框架版本。 There are some for the 3.5 → 4.0 transition here and here . 这里这里有一些3.5→4.0过渡。

For this particular change of versions, the difference comes up already whith an array or List<> of two elements, as your question shows. 对于这种特殊的版本更改,正如您的问题所示,差异已经出现了两个元素的数组或List<> Another simple example is: 另一个简单的例子是:

using System;
using System.Linq;

namespace SortTest
{
  static class Program
  {
    static void Main()
    {
      var arr = new[] { new { Name = "Mary", Age = 17, }, new { Name = "Louise", Age = 17, }, };

      Array.Sort(arr, (x, y) => x.Age.CompareTo(y.Age));

      Console.WriteLine(string.Join(",", arr.Select(x => x.Name)));
    }
  }
}

With .NET 4.0 this prints Louise,Mary . 使用.NET 4.0,可以打印出Louise,Mary The elements are swapped. 元素被交换。 However, with .NET 4.5 it prints Mary,Louise . 但是,使用.NET 4.5,它会打印Mary,Louise Note that the two girls have the same age. 请注意,这两个女孩的年龄相同。

List<>.Sort instance method and Array.Sort static method are documented to be non-stable sorts. List<>.Sort实例方法和Array.Sort静态方法被记录为非稳定排序。 They are free to leave elements of equal "size" in any order they want. 他们可以按照他们想要的任何顺序自由地留下相同“大小”的元素。 So your code must not make any assumptions about what order equivalent elements come in. 因此,您的代码不得对等效元素的顺序进行任何假设。

In contrast, Linq's OrderBy method performs a stable sort. 相比之下,Linq的OrderBy方法执行稳定的排序。 So 所以

var ordered = arr.OrderBy(x => x.Age);

is required to not swap Mary and Louise, given that they have the same Age . 要求 换玛丽·路易丝,因为它们具有相同的Age

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM