为什么从 ConditionalWeakTable 中删除键时 IEnumerator.MoveNext 不抛出异常?
Why doesn't IEnumerator.MoveNext throw when removing keys from a ConditionalWeakTable?
即使在枚举过程中修改了枚举集合,以下代码也不会抛出。
using System;
using System.Collections;
using System.Runtime.CompilerServices;
namespace ConsoleApp1
{
class MyKey
{
}
class Program
{
static void Main(string[] args)
{
ConditionalWeakTable<MyKey, string> table = new();
MyKey k1 = new();
MyKey k2 = new();
MyKey k3 = new();
table.Add(k1, "v1");
table.Add(k2, "v2");
table.Add(k3, "v3");
var enumerator = ((IEnumerable)table).GetEnumerator();
while(enumerator.MoveNext()) // no exception thrown
{
Console.WriteLine(enumerator.Current);
table.Remove(k1);
table.Remove(k2);
table.Remove(k3);
}
}
}
}
[ConsoleApp1.MyKey, v1]
这是故意的还是偶然的?如果是前者,那么在密钥被垃圾收集的情况下,什么会阻止抛出异常?
非常感谢!
按设计。
引用自the docs。
The returned enumerator does not extend the lifetime of any object pairs in the table, other than the current one. It does not return entries that have already been collected or that were added after the enumerator was retrieved. Additionally, it may not return all entries that were present when the enumerator was retrieved, for example, entries that were collected or removed after the enumerator was retrieved but before they were enumerated.
枚举器 Current
属性 指向的对象将不会被垃圾收集,可以安全访问。如果可枚举中更远的键被 GC 处理或删除,枚举器将不会访问该元素。
正如 canton7 在评论中提到的,这是 ConditionalWeakTable
保持线程安全所必需的 - 其他线程可能会在另一个线程的枚举期间删除元素。
即使在枚举过程中修改了枚举集合,以下代码也不会抛出。
using System;
using System.Collections;
using System.Runtime.CompilerServices;
namespace ConsoleApp1
{
class MyKey
{
}
class Program
{
static void Main(string[] args)
{
ConditionalWeakTable<MyKey, string> table = new();
MyKey k1 = new();
MyKey k2 = new();
MyKey k3 = new();
table.Add(k1, "v1");
table.Add(k2, "v2");
table.Add(k3, "v3");
var enumerator = ((IEnumerable)table).GetEnumerator();
while(enumerator.MoveNext()) // no exception thrown
{
Console.WriteLine(enumerator.Current);
table.Remove(k1);
table.Remove(k2);
table.Remove(k3);
}
}
}
}
[ConsoleApp1.MyKey, v1]
这是故意的还是偶然的?如果是前者,那么在密钥被垃圾收集的情况下,什么会阻止抛出异常?
非常感谢!
按设计。
引用自the docs。
The returned enumerator does not extend the lifetime of any object pairs in the table, other than the current one. It does not return entries that have already been collected or that were added after the enumerator was retrieved. Additionally, it may not return all entries that were present when the enumerator was retrieved, for example, entries that were collected or removed after the enumerator was retrieved but before they were enumerated.
枚举器 Current
属性 指向的对象将不会被垃圾收集,可以安全访问。如果可枚举中更远的键被 GC 处理或删除,枚举器将不会访问该元素。
正如 canton7 在评论中提到的,这是 ConditionalWeakTable
保持线程安全所必需的 - 其他线程可能会在另一个线程的枚举期间删除元素。