应该为非编译器目的使用ConditionalWeakTable<TKey, TValue>吗?

33
我最近在寻找一个使用弱引用的IDictionary,并在这里这里的答案中发现了ConditionalWeakTable<TKey,TValue>类。

有一篇权威的MSDN文章介绍了这个类,并指出:

你可以在 System.Runtime.CompilerServices 命名空间中找到这个类。之所以它在 CompilerServices 中是因为它不是通用的字典类型:我们打算让它只能被编译器编写者使用。

稍后又说:

......条件弱表并不是一个通用的集合......但如果您正在编写自己的.NET语言,并需要公开将属性附加到对象的能力,那么您一定要研究条件弱表。

与此相符合的是,该类的MSDN条目描述如下:

使编译器能够动态地将对象字段附加到托管对象。

很明显,它最初是为了帮助DLR而创建的,而System.Runtime.CompilerServices命名空间体现了这一点。但它似乎发现了比这更广泛的用途 - 即使在CLR内部也是如此。例如,在ILSpy中搜索ConditionalWeakTable的引用时,我可以看到它被用于MEF类CatalogExportProvider和内部WPF DataGridHelper类等中。

我的问题是,除了编译器编写和语言工具之外,是否可以在其他地方使用ConditionalWeakTable,以及这样做是否存在额外开销或实现在未来的.NET版本中发生重大变化的风险。(或者应该避免使用它,而改用自定义实现,比如这个)。

这里还有更多阅读材料:此处, 此处此处,介绍了ConditionalWeakTable如何利用隐藏的CLR实现弱引用(通过System.Runtime.Compiler.Services.DependentHandle)来解决键和值之间循环引用的问题,以及为什么无法轻松地以自定义方式完成此操作。

1个回答

23

我认为使用ConditionalWeakTable没有任何问题。如果你需要ephemerons,那么你几乎没有其他选择。

我认为未来的.NET版本不会有问题——即使只有编译器会使用这个类,Microsoft也无法更改它而不破坏现有二进制文件的兼容性。

至于开销——与普通字典相比,肯定会有开销。拥有许多DependentHandle可能会很昂贵,就像许多WeakReference比正常引用更昂贵一样(GC必须执行额外的工作来扫描它们以查看是否需要将其置空)。但是,除非您有大量(数百万)的条目,否则这不是问题。


谢谢,我会将其标记为答案。我认为你是对的 - 我想要一个使用弱引用的字典,因此ConditionalWeakTable与使用弱引用的任何其他实现相比不应该引入更多开销,并且还可以使用虚拟引用的优点。 - rikoe
我非常期待使用ConditionalWeakTable,但我在文档中注意到了这一点:“您无法通过覆盖Object.GetHashCode来明确设置键的哈希码来控制相等性比较。ConditionalWeakTable<TKey、TValue>类不使用Object.GetHashCode方法来计算哈希码,因此不会调用Object.GetHashCode覆盖。”-这使得它对我的目的没有用处。 :( - ctrlplusb
7
@Sean: ConditionalWeakTable 使用的键只能使用引用标识(identity),因为它无法确定何时不再有代码提供与集合中项匹配的键,这是不可能的(停机问题)。 - supercat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接