我最近在寻找使用弱引用的IDictionary
时遇到了ConditionalWeakTable<TKey,TValue>
类,正如此处和此处的答案中所建议的那样。
有一篇权威的 MSDN 文章介绍了该类,并指出:
您可以找到该类...在 System.Runtime.CompilerServices 命名空间中。它位于编译器服务中,因为它不是通用字典类型:我们打算仅由编译器编写者使用。
后来又说:
。条件弱表不打算成为通用集合...但是,如果您正在编写自己的 .NET 语言,并且需要公开将属性附加到对象的功能,则绝对应该查看条件弱表。
与此一致,该类的 MSDN 条目说明如下:
使编译器能够将对象字段动态附加到托管对象。
所以很明显,它最初是为一个非常具体的目的而创建的——帮助 DLR,而 System.Runtime.CompilerServices
命名空间体现了这一点。但它似乎找到了比这更广泛的用途——即使在 CLR 中也是如此。例如,如果我在ILSpy中搜索ConditionalWeakTable的引用,我可以看到它在MEF类CatalogExportProvider
和内部WPF DataGridHelper
类
我的问题是,是否可以在编译器编写和语言工具之外使用 ConditionalWeakTable,以及这样做在产生额外开销或在未来 .NET 版本中实现发生重大变化方面是否存在任何风险。(或者应该避免它,而是使用像这样的自定义实现)。
这里、这里和这里还有进一步的阅读,关于 ConditionalWeakTable 如何利用星历的隐藏 CLR 实现(通过 System.Runtime.Compiler.Services. DependentHandle
)来处理键和值之间的循环问题,以及如何以自定义方式轻松完成。
我认为使用ConditionalWeakTable
没有任何问题。如果你需要星历表,你几乎别无选择。
我不认为未来的 .NET 版本会成为问题 - 即使只有编译器会使用这个类,Microsoft仍然无法在不破坏与现有二进制文件的兼容性的情况下更改它。
至于开销 - 与普通词典相比,肯定会有开销。拥有许多DependentHandle
可能会很昂贵,类似于有多少WeakReference
比普通引用更昂贵(GC 必须做额外的工作来扫描它们以查看是否需要将它们清空)。但这不是问题,除非你有很多(数百万)条目。