List 。在.NET 4.5中的行为从.NET 4.0改变了吗?

我在针对.NET 4.0的项目中进行了以下测试:

[TestFixture] public class Donkey { [Test] public void TestListSorting() { var expected = new[] { MockRepository.GenerateStub(), MockRepository.GenerateStub() }; var sorted = new List(expected); CollectionAssert.AreEqual(expected, sorted); sorted.Sort(); CollectionAssert.AreEqual(expected, sorted); } } 

如果我在仅安装了.NET 4.0的计算机上运行它,则会失败。 如果我在安装了.NET 4.5的机器上运行它,它会通过。

我假设在.NET 4.5中, Sort的实现已经改变,以便在排序每个从CompareTo返回0的对象列表时保持顺序。

现在,抛开这个测试的明显疯狂。 我知道依靠这种行为是很疯狂的。

当然这是一个突破性的变化? 本页未列出.NET 4.0和4.5之间的兼容性。

是否有一个原因? 我错过了什么吗? 是否有另一页显示实际的重大变化? 我应该坐下来停止恐慌吗?

我以前也回答过类似的问题 。 排序方法在4.5到4.0之间变化,从快速排序到内省排序 。

它实际上更快,但它仍然不是一个稳定的排序1 ,也就是说,通过保留相等项的顺序,每次执行具有相同的输出。 由于没有List.Sort实现是一个稳定的排序,我不认为你已经在上面运行你的unit testing足够的时间让它在两个运行时都出错?

我尝试用等效的代码和一个返回0的比较器自己重现它。有时候,在.NET 4.5和.NET 3.5中,列表顺序都被保留,有时则不然。

即使它确实将排序类型从稳定变为不稳定, 它也不是一个突破性的变化 。 使用的排序类型和确切的输出不是List.Sort合同的List.Sort 。 方法合同保证的所有内容都是根据所使用的比较器,您的项目将按排序顺序排列。

但有趣的是,因为[MSDN文档](http://msdn.microsoft.com/en-us/library/b0zbh7b6.aspx)仍然说它使用QuickSort(通过`Array.Sort`),但这是如果您要逐步浏览.NET参考源,则不然。


1 根据使用HeapSortHeapSort混合的定义,它应该是不稳定的排序。 算法的设计者David Musser甚至在他的论文中指出:

像快速排序一样,Introsort不稳定 – 不保留等效元素的顺序 – 因此仍然需要对稳定的排序例程有单独的要求。

List.Sort 的规范说使用的排序是不稳定的,因此可能无法保持相等元素的排序; 它没有指定相等元素的特定重新排序,因此您无法真正将此更改称为重大更改。

正如@Rawling所说,看一下Sort()的文档 :

此实现执行不稳定的排序; 也就是说,如果两个元素相等,则可能不会保留它们的顺序。

因此,您正在尝试测试明确记录为未定义的内容。 这不是一个突破性的变化。

我没有看到任何变化。 正如其他人已经写过的,两个版本都执行不稳定的排序 这意味着您不能依赖于等于比较的元素的顺序。 他们的订单在排序期间可能会也可能不会改变 这肯定不是一个突破性的变化。

请参阅: List .Sort的文档

来自MSDN

此实现执行不稳定的排序; 也就是说,如果两个元素相等,则可能不会保留它们的顺序

看起来订单不可靠,因此测试无效。 另外,为什么要测试Sort方法呢? 对我来说似乎是不必要的考验。

像这样的问题经常会出现新的框架版本。 这里和这里有一些3.5→4.0过渡。

对于这种特定的版本更改,正如您的问题所示,差异已经出现了两个元素的数组或List<> 。 另一个简单的例子是:

 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))); } } } 

使用.NET 4.0,可以打印出Louise,Mary 。 元素被交换。 但是,使用.NET 4.5,它会打印Mary,Louise 。 请注意,这两个女孩的年龄相同。

List<>.Sort实例方法和Array.Sort静态方法被记录为非稳定排序。 他们可以按照他们想要的任何顺序自由地留下相同“大小”的元素。 因此,您的代码不得对等效元素的顺序进行任何假设。

相比之下,Linq的OrderBy方法执行稳定的排序。 所以

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

因为他们有相同的Age ,所以不要交换Mary和Louise。