字典方法 Remove 和 Clear (.NET Core) 在枚举期间修改集合。没有抛出异常

Dictionary methods Remove and Clear (.NET Core) modify the collection during enumeration. No exception thrown

我正在尝试为 enumerating collections safely, and I am checking if all modifications of the built-in collections are triggering an InvalidOperationException to be thrown by their respective enumerators. I noticed that in the .NET Core platform the Dictionary.Remove and Dictionary.Clear 方法实现缓存机制,但不会触发此异常。这是错误还是功能?

示例Remove

var dictionary = new Dictionary<int, string>();
dictionary.Add(1, "Hello");
dictionary.Add(2, "World");
foreach (var entry in dictionary)
{
    var removed = dictionary.Remove(entry.Key);
    Console.WriteLine($"{entry} removed: {removed}");
}
Console.WriteLine($"Count: {dictionary.Count}");

输出:

[1, Hello] removed: True
[2, World] removed: True
Count: 0

示例Clear

var dictionary = new Dictionary<int, string>();
dictionary.Add(1, "Hello");
dictionary.Add(2, "World");
foreach (var entry in dictionary)
{
    Console.WriteLine(entry);
    dictionary.Clear();
}
Console.WriteLine($"Count: {dictionary.Count}");

输出:

[1, Hello]
Count: 0

预期的异常是:

InvalidOperationException: Collection was modified; enumeration operation may not execute.

...由方法 Add 和 .NET Framework 中的相同方法抛出。

.NET 核心 3.0.0、C# 8、VS 2019 16.3.1、Windows 10

对于 Dictionary<TKey, TValue>,这似乎是 .Net 完整框架和 .Net 核心之间的故意差异。

分歧发生在Pull #18854: Remove version increment from Dictionary.Remove overloads:

Removes the version increment from Remove operations

This addresses the coreclr side of the api change Add Dictionary.Remove(predicate) with the intention of allowing removal of items from the dictionary while enumerating per direction from @jkotas . All collections tests and modified and new tests added in the related corefx PR.

似乎有一个未解决的文档问题:

Issue #42123: Clarify Dictionary behavior/guarantees around mutation during enumeration:

Is it correct to say that the current implementation of Dictionary supports non-concurrent mutation during iteration?

仅删除。这是在 dotnet/coreclr#18854.

中作为一项功能启用的

is this something that can be depended on going forward

是的。

我们应该确保更新文档以反映这一点。

您可能想对打开的文档问题添加投票以请求澄清,因为 .Net core 3.0 documentation for Dictionary<TKey,TValue>.GetEnumerator() 现在 已过时:

If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and the next call to MoveNext or IEnumerator.Reset throws an InvalidOperationException.

奇怪的是,SortedDictionary<TKey, TValue> 的枚举器 在枚举期间修改字典时会抛出。

演示:

澄清更改何时可用以及通过哪些方法...

Microsoft 关于字典 .Remove and .Clear 的文档已更新:

.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 附带 C# 8.0。从那时起,我们只能通过 .Remove and .Clear 在枚举 (foreach) 期间修改 Dictionary