ilovecomputer66 发表于 2023-5-25 08:55

我发现.NET 6以后,C# 的dictionary可以foreach时删除了,有官方说明网页么?怎么...

之前framework不允许的

有官方说明网页么?怎么就可以了。chatgpt给不出官网页面(他老是想当然造个404的)

GitHubList 发表于 2023-5-25 10:24

你的代码写法有问题而已...

dictionary可以foreach,但不能foreach的同时删除,不然会报错

同理类似数组一样,for循环的时候,删了一个元素,会导致索引超出

以下为正确写法

// 假设要删除值为 "value" 的键值对
Dictionary<string, string> dict = new Dictionary<string, string>();
// 添加一些元素
dict.Add("key1", "value1");
dict.Add("key2", "value2");
dict.Add("key3", "value3");

// 使用迭代器进行遍历
var keysToRemove = new List<string>();
foreach (var pair in dict)
{
    if (pair.Value == "value")
    {
      keysToRemove.Add(pair.Key);
    }
}
// 删除需要删除的键
foreach (var key in keysToRemove)
{
    dict.Remove(key);
}

披星代月 发表于 2023-5-25 11:30

https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs,d3599058f8d79be0
Dictonary 对应的源码 ,自己研究吧,参考9# 的回复。

1sina 发表于 2023-5-25 09:07

披星代月 发表于 2023-5-25 09:47

不太理解你的意思。举个demo说下。

ilovecomputer66 发表于 2023-5-25 10:17

披星代月 发表于 2023-5-25 09:47
不太理解你的意思。举个demo说下。

Dictionary<string,int> students=new Dictionary<string, int>();
students.Add("xiaoming",90);
students.Add("xiaohong",80);
students.Add("xiaolan",70);
foreach(KeyValuePair<string,int> stu in students){
   if(stu.Value<80){
          students.Remove(stu.Key);
   }
}


.net 6运行正常,而以前版本 framework,全都报错,不允许foreach中删除

jidesheng6 发表于 2023-5-25 10:22

ilovecomputer66 发表于 2023-5-25 10:17
Dictionary students=new Dictionary();
students.Add("xiaoming",90);
students.Add("xiaohong",80);
...

不太清楚和你遇到的是不是一样的,之前foreach里面直接去操作迭代的变量,会提示不允许,需要重新设置一个新变量把迭代变量赋值给它,然后才可以操作

zhangpan0912 发表于 2023-5-25 11:02

原理就和list集合差不多。

list在循环的过程中也不能直接删除。

wanxu 发表于 2023-5-25 11:09

ilovecomputer66 发表于 2023-5-25 10:17
Dictionary students=new Dictionary();
students.Add("xiaoming",90);
students.Add("xiaohong",80);
...

Dictionary<string, int> students = new Dictionary<string, int>();
            students.Add("xiaoming", 90);
            students.Add("xiaohong", 80);
            students.Add("xiaolan", 70);
            foreach (KeyValuePair<string, int> stu in students)
            {
                if (stu.Value < 80)
                {
                  students.Remove(stu.Key);
                }
            }
            foreach (var item in students)
            {
                Console.WriteLine($"key:{item.Key}--value:{item.Value}");
            }


在.net6里的确不会报错并且成功删除了一个指定元素,但是我尝试在list中仍然会报错

pjy612 发表于 2023-5-25 11:25

本帖最后由 pjy612 于 2023-5-25 12:53 编辑

问了下 GPT 答复是


在 .NET 6 中,你可以在对 Dictionary 进行 foreach 循环时删除元素,而在较早版本的 .NET Framework 中不行的原因是因为这两个版本中 Dictionary 的实现方式不同。

在 .NET Framework 中,Dictionary 类是基于哈希表实现的。在使用 foreach 循环遍历时,迭代器会先获取一个快照(snapshot)来保证在遍历过程中对字典的修改不会影响迭代过程。因此,如果在循环中尝试删除元素,会导致迭代器失效,并抛出一个异常。

然而,在 .NET 6 中,Dictionary 类经过了优化和重构,采用了不同的实现方式。新的实现使用了一个单向链表和一个哈希表,它支持在循环中删除元素。这是因为在新的实现中,字典的修改不会导致迭代器失效。通过在删除元素时更新链表和哈希表的引用,可以在循环中安全地删除元素。

总结起来,.NET 6 中的 Dictionary 实现了对循环中删除元素的支持,而 .NET Framework 中的 Dictionary 不支持此操作,因为它的实现方式不同,导致在循环中删除元素会导致迭代器失效。


但是 具体的细节 可能要查官方的代码了,或者去 GitHub 上 搜下源码。

官方源码不知道挪到哪儿了,找了个镜像的...

MoveNext
https://github.com/lodejard/AllNetCore/blob/3355ebc21d5f1f72417831c60bd030ead4802a37/dotnet/coreclr/src/mscorlib/src/System/Collections/Generic/Dictionary.cs#L734

Remove
https://github.com/lodejard/AllNetCore/blob/3355ebc21d5f1f72417831c60bd030ead4802a37/dotnet/coreclr/src/mscorlib/src/System/Collections/Generic/Dictionary.cs#L485

官方的源码
https://github.com/dotnet/runtime/blob/release/7.0/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs#L966

拓展:
通过关键词 在谷歌中检索: .net core 3.0 Dictionary Enumerator remove
得到相关链接:
https://stackoverflow.com/questions/58617273/dictionary-methods-remove-and-clear-net-core-modify-the-collection-during-enu
https://github.com/dotnet/coreclr/pull/18854
https://github.com/dotnet/runtime/issues/31341
https://github.com/dotnet/runtime/issues/31303
https://stackoverflow.com/questions/66939923/what-changed-in-net-5-that-makes-it-not-throw-when-changing-dictionary-values-i


PS:
感觉有种 那些 java条主 对 一些源码上的细节抽丝剥茧完了,然后 写个文章 。。。接着这玩意就纳入 八股文 豪华套餐。。。 的既视感。。。{:301_978:}

wxk0248 发表于 2023-5-25 11:29

https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.remove?view=net-7.0
Remarks
If the Dictionary<TKey,TValue> does not contain an element with the specified key, the Dictionary<TKey,TValue> remains unchanged. No exception is thrown.

This method approaches an O(1) operation.

.NET Core 3.0+ only: this mutating method may be safely called without invalidating active enumerators on the Dictionary<TKey,TValue> instance. This does not imply thread safety.
从.net core 3.0开始Dictionary就可以在枚举时候删除元素了
页: [1] 2
查看完整版本: 我发现.NET 6以后,C# 的dictionary可以foreach时删除了,有官方说明网页么?怎么...