冲压/标记/标记对象实例

时间:2013-06-12 15:50:36

标签: .net-4.0 metadata

我有一个例程,它接受一个对象并对其进行一些处理。对象可能也可能不是可变的。

void CommandProcessor(ICommand command) {
    // do a lot of things
}

同一命令实例有可能在处理器中循环。当发生这种情况时,事情就变得讨厌我想检测这些返回访问者并阻止他们被处理。问题是我怎样才能透明地做到这一点,即不打扰对象本身。

这是我试过的

  • Boolean Visited {get, set}上添加了属性ICommand

我不喜欢这个,因为一个模块的逻辑显示在其他模块中。 ShutdownCommand关注的是关闭,而不是簿记。此外,EatIceCreamCommand可能始终返回False,希望获得更多。一些非可变对象与setter有完全不同的问题。

  • 私下维护所有已处理实例的查找表。当一个对象首先检查列表时。

我也不喜欢这个。 (1)表现。查找表变大了。我们需要进行线性搜索以匹配实例。 (2)不能依赖hashcode。该对象可能不时伪造不同的哈希码。 (3)将对象保留在列表中可防止它们被垃圾收集。

我需要一种方法在实例(ICommand)上放置一些不可见的标记,只有我的代码可以看到。目前我不区分调用。只是祈祷相同的情况不要回来。有没有人有更好的想法来实现这个功能..?

1 个答案:

答案 0 :(得分:3)

假设你无法阻止这种情况发生在逻辑上(尝试切断循环),我会选择你已经看过的HashSet个命令。

即使对象违反了HashCodeEquals的合同(我将其视为问题),您也可以创建自己的IEqualityComparer<ICommand>使用{{3}非虚拟地调用Object.GetHashCodeEquals方法只会测试参考标识。因此,您的池将包含不同的实例,而不关心命令是否或如何覆盖EqualsGetHashCode

这就留下了积累垃圾的问题。假设您没有定期清除池的选项,可以使用System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(或.NET 4的非泛型WeakReference类)来避免保留对象。然后,您会经常发现所有“死”的弱引用,以防止累积那些。 (在这种情况下,您的比较器实际上是IEqualityComparer<WeakReference<T>>,比较弱引用的目标以确定身份。)

它不是特别优雅,但我认为这是设计中固有的 - 你需要处理一个命令来改变状态,并且一个不可变对象不能按定义改变状态,所以你需要命令之外的状态。哈希集似乎是一种相当合理的方法,希望我已经明确表示如何避免你提到的所有三个问题。

编辑:我没有考虑的一件事是使用WeakReference<T>使得删除条目变得很困难 - 当原始值被垃圾收集时,你将无法再找到它的哈希码。您可能需要使用仍然有效的条目创建新的HashSet。或者使用您自己的LRU缓存,如评论中所述。