C# 在.NET5中发生了什么变化,使得它在foreach中更改字典值时不会抛出

C# 在.NET5中发生了什么变化,使得它在foreach中更改字典值时不会抛出,c#,.net-5,C#,.net 5,在.NET中,字典的源代码发生了更改,以允许在枚举期间更新现有密钥。它是由Stephen Toub于2020年4月9日提交的。可以找到该提交以及相应的 PR标题为“允许在枚举期间覆盖词典”,并指出它修复了“考虑从词典中的覆盖中删除\u version++”。该期由图布先生主持开幕,全文如下: 以前,我们在从数据库中删除ing时删除了\u version++ 字典。我们应该考虑在刚刚改写时这样做。 字典中现有键的值。这将使 更新在字典中调整值的循环,而无需 采取复杂而昂贵的措施 对此问题的评论要求

在.NET中,
字典
的源代码发生了更改,以允许在枚举期间更新现有密钥。它是由Stephen Toub于2020年4月9日提交的。可以找到该提交以及相应的

PR标题为“允许在枚举期间覆盖词典”,并指出它修复了“考虑从
词典中的覆盖中删除
\u version++
”。该期由图布先生主持开幕,全文如下:

以前,我们在从数据库中删除ing时删除了
\u version++
字典。我们应该考虑在刚刚改写时这样做。 字典中现有键的值。这将使 更新在字典中调整值的循环,而无需 采取复杂而昂贵的措施

对此问题的评论要求:

这样做的好处是什么

斯蒂芬·图布:

正如在最初的帖子中所提到的,今天正在抛出的精细模式将开始正常工作,例如

foreach(dict中的KeyValuePair对)
dict[pair.Key]=pair.Value+1

如果查看
词典
,您可以看到
\u version
字段(用于检测修改)现在仅在某些条件下更新,而在修改现有密钥时不会更新

特别感兴趣的领域是方法(由索引器调用,见下文)及其类型为
InsertionBehavior
的第三个参数。当此值为InsertionBehavior.OverwriteeExisting时,不会更新现有密钥的版本控制字段

例如,请参见更新的
TryInsert

if(behavior==InsertionBehavior.OverwriteExisting)
{ 
条目[i]。值=值;
返回true;
}
在更改之前,该部分如下所示(代码注释):

if(behavior==InsertionBehavior.OverwriteExisting)
{ 
条目[i]。值=值;

_version++;//我认为我们应该能够在
字典的源代码中找到答案,从索引器
公共TValue this[TKey]{/*…*/}的
访问器开始读取
。应该存在一个私有字段来跟踪集合是否被修改。如果我使用setter
d[k]=tmp;
分配,并且
k
以前在
字典中,那么这算是修改吗?他们一定已经更改了。在旧版本中,他们没有
条目[I].value=value;version++;return;
在我们进行更新的分支中。
version++
确保枚举器在枚举器的下一个
MoveNext()
上爆炸时出现异常。(它们还允许使用值集合,例如
foreach(d.Values中的var v){Console.WriteLine(“Top”)+v+“”+d[“c”];d[“c”+=1;Console.WriteLine(“底部”+v+“”+d[“c”]);}
。因此,我猜键和值仍然只有一个
版本
字段。我在哪里可以看到新的
公共类词典的c#源代码
?)很好!在
词典.cs
文件中的更改(您答案中的提交链接)实际上与我预期的完全一样。我想知道对
List
进行更改是否也有意义?也就是说,当您执行
List[index]=newvalue;
(即索引器
set
访问器)时,这只会覆盖“slot”中的值这已经存在。因此这与
列表
的这一方面的解释有关。@JeppeStigNielsen谢谢。在我意识到我可以只看一下今天的文件历史lolAs之前,对git进行了大量挖掘,要实现我所说的
列表
中的更改,所需的一切就是删除。所以有人看到了吗g这可能会发出拉取请求并破坏另一个线程的答案(我之前的评论)。
var d = new Dictionary<string, int> { { "a", 0 }, { "b", 0 }, { "c", 0 } };
foreach (var k in d.Keys) 
{
   d[k]+=1;
}