.net - 任何弱实习集合(对于不可变对象(immutable对象))

标签 .net immutability weak-references string-interning

在某些涉及不可变对象(immutable对象)的情况下,可能会出现许多语义相同的不同对象。一个简单的例子是将文件中的多行文本读取为字符串。从程序的角度来看,两行具有相同字符序列的事实将是“巧合”,但从程序员的角度来看,可能会出现大量重复。如果许多字符串实例是相同的,将这些不同实例的引用更改为对单个实例的引用将节省内存,并且还有助于它们之间的比较(如果两个字符串引用指向同一个字符串,则无需执行字符-按字符比较以确定它们是相同的)。

对于某些情况,系统提供的字符串实习工具可能很有用。但是,它有几个严重的限制:

  • 一旦字符串被实习,该实习副本将永远存在,无论是否存在对它的任何其他引用
  • 字符串实习工具仅适用于字符串,不能用于任何其他不可变类型。

  • 如果存在真WeakDictionary<ImmutableClassType, ImmutableClassType> (对于每个元素,键和值都是相同的),代码可以执行以下操作:
    if (theDict.TryGetValue(myString, ref internedString))
      myString = internedString;
    else
      theDict[myString] = myString;
    

    不幸的是,我不知道任何内置 WeakDictionary<keyType, valType> .net 中的类。此外,为每个项目的键和值生成弱引用似乎很浪费,因为这两个引用总是指向同一事物。

    我读过一些关于 ConditionalWeakTable ,这听起来像是一个有趣的类,但我不认为它在这里可用,因为目标是能够采用一个实例并找到另一个语义等效的独立实例。

    对于类的实例具有明确定义的生命周期的情况,使用传统的 Dictionary 可能是合理的。合并相同的实例。然而,在许多情况下,可能很难知道这样的 Dictionary 何时出现。应丢弃或清除其中的元素。一个 WeakReference基于实习收集将避免此类问题。这样的事情是否存在,或者是否可以轻松实现?

    附录
    正如 svick 所指出的,Dictionary<WeakReference, WeakReference>会有些问题,因为没有实际的方法来定义 IEqualityComparer这将有一个现场WeakReference返回 GetHashCode其目标的值,并有一个死者继续返回该值。可以定义一个结构体,它包含一个整数目标哈希码值(在构造函数中设置),以及它自己的 GetHashCode将返回该整数。稍微改进可能是使用 ConditionalWeakTable链接 WeakReference 的目标到可用于将表项排入队列以进行删除的可终结对象。

    我不确定在急切地清理字典与采取更被动的方法之间的适当平衡是什么(例如,如果自上次扫描以来至少有一次 GC,则在添加项目时执行扫描,以及数量自上次扫描以来添加的项目数量超过了幸存下来的项目数量)。浏览字典中的所有内容都不会免费,但 ConditionalWeakTable 可能也不会免费。

    缴费灵
    我正在考虑的另一个概念,但我认为它可能不像弱实习方法那么有用,就是让逻辑上不可变的类型保存可变的“时间戳”值,并有一个比较方法接受它的参数来自 ref .如果发现两个不同的实例相等,则将检查它们的时间戳值。如果两者都为零,则将从全局计数器(-1、-2、-3 等)中为它们分配连续的负数。具有(或被分配)较低时间戳值的参数将被另一个替换。

    使用这种方法,如果许多对象实例被重复地相互比较,许多引用将被替换为对“较旧”实例的引用。根据使用模式,这可能导致大多数相同的对象实例在不使用任何类型的实习字典的情况下被合并。但是,对嵌套对象应用这种方法将要求“不可变”对象允许将嵌套对象引用改变为指向其他假定相同的嵌套对象。如果“假定相同”的对象总是如此,这应该没问题,但如果不是,则可能会导致相当奇怪的不当行为。

    最佳答案

    您可以创建类似 Dictionary<WeakReference, WeakReference> 的内容使用自定义的相等比较器并在适当的时候修剪那些不再存在的人。一个问题是如何移除一个死人 WeakRefrence从字典中,因为你不能通过引用相等(记住,你必须使用自定义相等比较器)或索引来删除它。可能的解决方案是创建一个继承自 WeakReference 的类型。并且即使引用已死也有正确的哈希码。或者您可以将其包装在自定义 struct 中.

    但是正如您所说,如果每个引用文献在死亡后立即从字典中删除,那就太好了。我认为做到这一点的唯一方法是以某种方式使用终结器。但是如果您不想(或不能)修改字典中的类型,这将变得非常复杂。

    基本思想是,您将拥有与上述相同的弱引用字典(有关如何删除项目的警告仍然适用),但您还使用 ConditionalWeakTable 将带有终结器的辅助对象附加到字典中的每个项目。 .在该终结器中,您将从字典中删除该项目。因为如何ConditionalWeakTable有效,如果字典中的一个项目被 GC,附加的对象也会被 GC,这意味着它的终结器将被调用,因此该项目将从字典中删除

    关于.net - 任何弱实习集合(对于不可变对象(immutable对象)),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10923682/

    相关文章:

    c# - 在私有(private)字段中使用 Bcl ImmutableDictionary

    objective-c - 有没有办法显示不使用弱 self 的警告?

    swift - 在 Swift 中相互引用的两个弱变量?

    c# - 取消执行并在方法重新进入时重新执行

    c# - GitSharp 与 NGit

    python - os.path.exists 不接受变量输入

    clojure - Clojure 中的弱引用

    .net - 在 Visual Studio 2015 中调试时值不正确

    c# - 读取从 "Scanners and Cameras"打开的文件会抛出 UnauthorizedAccessException

    java - Findbugs 不会检测到用户定义的类对内部表示的暴露