C# 哈希集上的LINQ顺序敏感操作是确定性的吗?

C# 哈希集上的LINQ顺序敏感操作是确定性的吗?,c#,linq,C#,Linq,原始描述: 我正在处理单线程同步逻辑,我开始观察输出中的一些差异,这取决于我是在调试模式还是发布模式下运行代码。我开始怀疑决定论的缺失是从哪里来的。我大量使用LINQ,所以我想可能是像HashSet这样没有固有顺序的集合导致了这个问题 如果它们不是确定性的,那么会产生一些有趣的结果,例如,First()实际上是一个随机元素,可能具有一些不明显的概率分布 进一步解释: 我不在乎排序的标准。具体来说,我不在乎它是否是插入顺序。我只询问是否在HashSet上的顺序敏感操作之间设置并共享了顺序,而没有任

原始描述:

我正在处理单线程同步逻辑,我开始观察输出中的一些差异,这取决于我是在调试模式还是发布模式下运行代码。我开始怀疑决定论的缺失是从哪里来的。我大量使用LINQ,所以我想可能是像HashSet这样没有固有顺序的集合导致了这个问题

如果它们不是确定性的,那么会产生一些有趣的结果,例如,First()实际上是一个随机元素,可能具有一些不明显的概率分布

进一步解释:

我不在乎排序的标准。具体来说,我不在乎它是否是插入顺序。我只询问是否在HashSet上的顺序敏感操作之间设置并共享了顺序,而没有任何更改

举例说明:

我有一个不依赖于任何状态的方法来创建哈希集。它将一些元素放入并返回First()

  • 我是否保证在方法调用之间总是相同的元素

  • 当整个应用程序终止并再次执行时,它会是同一个元素吗

若这些问题的答案都是否定的,那个么对我来说,这意味着从程序员的角度来看,HashSet上对LINQ顺序敏感的操作并没有确定性。再一次,我不需要知道排序标准(内部使用的比较器)

如果它们不是确定性的,那么会有一些有趣的结果 结果,比如说,First()实际上是随机的 具有潜在不明显概率分布的元素

需要注意的是,此处的两个选项未定义随机。事实上,有-已定义的未定义的未定义并不意味着随机不可预测——它必须意味着我什么也不承诺

明确指出:

HashSet类提供高性能的set操作。一套 是一个不包含重复元素的集合,其 元素没有特定的顺序。(强调我的)


如果您想对订单有把握(或者希望它是确定性的),那么您需要使用
OrderBy
,或者其他类型(例如
SortedSet
)。

简而言之,除非您使用
OrderBy
,否则订单将无法定义。现有的实现可能会以特定的方式进行排序,但这是一个实现细节,而不是合同的一部分。您不应该依赖于
HashSet
的顺序,但无论如何它都不应该更改。值得一读,因为相关:@SzymonBrych可能与当前实现重复,只要您从未删除项,那么它将始终是相同的元素。但这只是一个实施细节,不是合同的一部分。因此,例如,当您更新.NET Framework版本时,它可能会更改。如果您想要明确的订单,您必须使用
OrderBy
@SzymonBrych:yes,直到您不删除为止。但这可能会随着下一个框架而改变,您不应该依赖它。你读过我上面链接的J.Skeets的答案吗?还有其他可以保证订单的集合。当然,您也可以使用hashSet.OrderBy(x=>something.First()。但是如果你总是这样做,你就会使用错误的集合,因为它效率很低。但是,除非引入一些熵,否则在某些情况下,项目总是以相同的顺序返回(在连续运行中)。如果项目具有确定性哈希代码,并且以相同的顺序添加(始终是AB C),那么它们将始终以相同的顺序返回(即使是AB)当前实现,yes@matthewstorples。但这不是合同的一部分。这就是undefined的关键部分——通过说元素没有特定的顺序,MS可以自由地更改实现细节(而不会违反合同——因为它没有承诺任何东西)。@Matthewstorples我想定义熵是什么是不切实际的?不连续运行如何?@mjwills我理解,假设顺序决定论是一种不好的做法,因为无论当前状态如何,都不能保证它。@mjwills同意,我只是想帮助澄清您对未定义和随机的定义