.net 4.0 标记/标记/标记对象实例

.net 4.0 标记/标记/标记对象实例,.net-4.0,metadata,.net 4.0,Metadata,我有一个接受对象并对其进行处理的例程。对象可能是可变的,也可能不是可变的 void CommandProcessor(ICommand command) { // do a lot of things } 同一个命令实例很可能在处理器中循环。当这种情况发生时,事情就变得糟糕了。我想检测这些回访者并阻止他们被处理。问题是我如何透明地做到这一点,即不干扰对象本身 下面是我所尝试的 在ICommand上添加了属性Boolean{get,set} 我不喜欢这个,因为一个模块的逻辑在另一个模

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

void CommandProcessor(ICommand command) {
    // do a lot of things
}
同一个命令实例很可能在处理器中循环。当这种情况发生时,事情就变得糟糕了。我想检测这些回访者并阻止他们被处理。问题是我如何透明地做到这一点,即不干扰对象本身

下面是我所尝试的

  • ICommand
    上添加了属性
    Boolean{get,set}
我不喜欢这个,因为一个模块的逻辑在另一个模块中出现。
shutdown命令
与关闭有关,而与记账无关。另外,
eaticecream命令
可能总是返回
False
,希望获得更多。一些不可变的对象在setter上有明显的问题

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

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


我需要一种方法在实例(ICommand)上放置一些只有我的代码才能看到的不可见标记。目前我不区分调用。祈祷同样的事情不再发生。是否有人有更好的想法来实现此功能

假设您无法从逻辑上阻止这种情况发生(尝试切断循环),我会选择您已经看到的
HashSet

即使对象违反了
HashCode
Equals
(我将从中看到问题开始)的合同,您也可以创建自己的
IEqualityComparer,该工具用于调用
Object.GetHashCode
非实质上。
Equals
方法只是测试引用标识。因此,您的池将包含不同的实例,而不关心命令是否覆盖或如何覆盖
Equals
GetHashCode

这就留下了垃圾堆积的问题。假设您没有定期清除池的选项,您可以使用(或.NET 4的非泛型
WeakReference
类)来避免保留对象。然后,您会经常发现所有“死”弱引用,以防止这些引用的累积。(在本例中,您的比较器实际上是一个
IEqualityComparer
,用于比较标识的弱引用的目标。)

它不是特别优雅,但我认为这是设计中固有的——你需要处理一个命令来改变某个地方的状态,而一个不变的对象不能根据定义改变状态,所以你需要命令之外的状态。散列集似乎是一种相当合理的方法,希望我已经清楚地说明了如何避免您提到的所有三个问题


编辑:我没有考虑的一件事是,使用
WeakReference
很难删除条目-当原始值被垃圾收集时,您将无法再找到其哈希代码。您可能只需要创建一个新的
HashSet
,其中包含仍然活动的条目。或者使用您自己的LRU缓存,如注释中所述。

您能否澄清“实例上的不可见标记”是指ICommand的实例,还是“CommandProcessor”所有者的实例?@GarryVass ICommand的实例。(这样我可以检测它何时再次进入。)我将创建一个从ICommand继承并用于所需实例的内部接口,并从ICommand声明ShutdownCommand。顺便说一句,我检查了是否可以使用自定义属性玩有趣的游戏,但事实并非如此。“对象可能会不时伪造不同的哈希代码”-这听起来像是从…@JonSkeet开始的“对象可能不时伪造不同的哈希代码”,因为哈希代码取决于该对象的内部状态(基于实例字段或属性的值).Immutable对象将遵守其哈希代码,但我不知道一个实现是否是不可变的。不同的实现可能会有所不同。谢谢。
System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode
是一个很好的帮助。它的文档在您关心对象标识的情况下非常有用。谢谢那就是。
WeakReference
在4.5中,但我仍然坚持使用4.0。因此引用累积仍然是一个问题。但我可以使用类似LRU缓存的东西,并删除超过15分钟的条目。