有没有一种方法可以获得实例的唯一标识符?
GetHashCode()
对于指向同一实例的两个引用是相同的。但是,两个不同的实例可以(很容易地)获得相同的哈希码:
Hashtable hashCodesSeen = new Hashtable();
LinkedList<object> l = new LinkedList<object>();
int n = 0;
while (true)
{
object o = new object();
// Remember objects so that they don't get collected.
// This does not make any difference though :(
l.AddFirst(o);
int hashCode = o.GetHashCode();
n++;
if (hashCodesSeen.ContainsKey(hashCode))
{
// Same hashCode seen twice for DIFFERENT objects (n is as low as 5322).
Console.WriteLine("Hashcode seen twice: " + n + " (" + hashCode + ")");
break;
}
hashCodesSeen.Add(hashCode, null);
}
我正在编写一个调试插件,需要获取某种在程序运行期间唯一的引用ID。
我已经成功获取了实例的内部地址,在垃圾回收器(GC)压缩堆之前是唯一的(移动对象=更改地址)。
Stack Overflow问题 Default implementation for Object.GetHashCode() 可能与此相关。
由于我是使用调试器API访问程序中的对象,因此这些对象不在我的控制之下。如果我能够控制这些对象,添加自己的唯一标识符将非常简单。
我想要为构建哈希表ID -> object获取唯一的ID,以便查找已经看到的对象。目前我是这样解决的:
Build a hashtable: 'hashCode' -> (list of objects with hash code == 'hashCode')
Find if object seen(o) {
candidates = hashtable[o.GetHashCode()] // Objects with the same hashCode.
If no candidates, the object is new
If some candidates, compare their addresses to o.Address
If no address is equal (the hash code was just a coincidence) -> o is new
If some address equal, o already seen
}
ConditionalWeakTable
可能更好,因为它只会在对象存在引用时保留其表示。此外,我建议使用Int64
而不是 GUID,因为它允许对象被赋予持久的 等级。这些东西在锁定场景中可能很有用(例如,如果所有需要获取多个锁的代码都按照某个定义的顺序执行,则可以避免死锁,但要使其起作用,必须 存在 定义的顺序)。 - supercatlong
,你的场景可能不同,例如在分布式系统中,使用GUID
更有用。至于ConditionalWeakTable
:你是对的;DependentHandle
检查存活性(注意:仅当事物调整大小时!),这在这里可能很有用。但是,如果需要性能,则锁定可能成为问题,因此在这种情况下,使用这个可能会很有趣...老实说,我个人不喜欢ConditionalWeakTable
的实现方式,这可能导致我倾向于使用简单的Dictionary
- 即使你是正确的。 - atlasteConditionalWeakTable
的实际工作原理感到好奇。它仅允许添加项的事实使我认为它旨在最小化与并发相关的开销,但我不知道它内部是如何工作的。我确实觉得有点奇怪的是,没有一个简单的DependentHandle
包装器不使用表格,因为肯定有时需要确保一个对象在另一个对象的生命周期内保持活动状态,但后者没有空间引用第一个对象。 - supercatDependentHandle
中可以找到这些free调用,在调整大小阶段调用它们。 - atlaste