.NET唯一对象标识符

Mar*_*cek 113 c# unique hashcode gethashcode

有没有办法获取实例的唯一标识符?

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);
}
Run Code Online (Sandbox Code Playgroud)

我正在编写一个调试插件,我需要获取某种ID作为参考,这在程序运行期间是唯一的.

我已经设法获得实例的内部ADDRESS,这是唯一的,直到垃圾收集器(GC)压缩堆(=移动对象=更改地址).

Stack Overflow问题Object.GetHashCode()的默认实现可能是相关的.

这些对象不受我的控制,因为我正在使用调试器API访问正在调试的程序中的对象.如果我控制对象,添加我自己的唯一标识符将是微不足道的.

我想要用于构建哈希表ID - >对象的唯一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
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*Jon 69

仅限.NET 4及更高版本

好消息,大家好!

这项工作的完美工具是在.NET 4中构建的,它被称为ConditionalWeakTable<TKey, TValue>.这个班:

  • 可用于很像一个字典与被管理对象实例的任意数据相关联(尽管它不是一个字典)
  • 不依赖于内存地址,因此不受GC压缩堆的影响
  • 不会因为将对象作为键输入到表中而使对象保持活动状态,因此可以在不使对象中的每个对象永远存在的情况下使用它
  • 使用引用相等来确定对象标识; 移动,类作者无法修改此行为,因此可以在任何类型的对象上一致地使用它
  • 可以动态填充,因此不需要在对象构造函数中注入代码

  • 仅出于完整性考虑:ConditionalWeakTable依赖于RuntimeHelpers.GetHashCode和object.ReferenceEquals来进行内部工作。行为与使用这两种方法构建`IEqualityComparer &lt;T&gt;`相同。如果您需要性能,我实际上建议您这样做,因为`ConditionalWeakTable`对其所有操作都有锁以使其线程安全。 (5认同)

Jon*_*eet 40

引用对象的唯一标识符.我不知道有什么方法可以将它转换成类似字符串等的东西.在压缩过程中引用的值会发生变化(正如你所见),但是每个先前的值A都会变为值B,所以到目前为止就安全代码而言,它仍然是一个唯一的ID.

如果涉及的对象在您的控制之下,您可以使用弱引用(以避免垃圾回收)创建映射,从而引用您选择的ID(GUID,整数,等等).然而,这会增加一定的开销和复杂性.

  • @ SlippD.Thompson:不,它仍然是一对一的关系.只有一个引用值引用任何给定的对象.该值可能在内存中出现多次(例如,作为多个变量的值),但它仍然是单个值.这就像一个房子地址:我可以在多张纸上写下我的家庭住址,但这仍然是我家的标识符.任何两个不相同的引用值*必须*引用不同的对象 - 至少在C#中. (5认同)

sis*_*sve 40

检查出ObjectIDGenerator类?这就是你想要做的,以及Marc Gravell所描述的.

ObjectIDGenerator跟踪先前识别的对象.当您询问对象的ID时,ObjectIDGenerator会知道是返回现有ID,还是生成并记住新ID.

这些ID在ObjectIDGenerator实例的生命周期中是唯一的.通常,ObjectIDGenerator的生命周期与创建它的Formatter一样长.对象ID仅在给定的序列化流中具有意义,并且用于跟踪哪些对象在序列化对象图中具有对其他对象的引用.

使用哈希表,ObjectIDGenerator保留将哪个ID分配给哪个对象.唯一标识每个对象的对象引用是运行时垃圾收集堆中的地址.对象引用值可以在序列化期间更改,但表会自动更新,以便信息正确.

对象ID是64位数字.分配从一开始,因此零永远不是有效的对象ID.格式化程序可以选择零值来表示其值为空引用的对象引用(在Visual Basic中为Nothing).

  • Reflector告诉我,ObjectIDGenerator是一个依赖于默认GetHashCode实现的哈希表(即它不使用用户重载). (5认同)

Ant*_*lev 35

RuntimeHelpers.GetHashCode()可能有帮助(MSDN).

  • 一本备受尊敬的作者撰写的一本关于.NET的书指出,RuntimeHelpers.GetHashCode()将生成一个在AppDomain中唯一的代码,并且Microsoft可以将方法命名为GetUniqueObjectID.这是完全错误的.在测试中,我发现在创建10,000个对象实例(WinForms TextBox)时,我通常会得到一个副本,并且永远不会超过30,000.依赖于所谓的唯一性的代码在创建不超过许多对象的1/10之后导致生产系统中的间歇性崩溃. (41认同)
  • @supercat:啊哈 - 刚从2003年发现了一些来自.NET 1.0和1.1的证据.看起来他们计划改变.NET 2:http://blogs.msdn.com/b/brada/archive/2003/09/30/50396.aspx (3认同)
  • 这可能会有所帮助,但是有了成本 - IIRC,使用基础对象.GetHashCode()需要分配一个不是免费的同步块.不错的主意 - 来自我的+1. (2认同)

maj*_*tor 7

你可以在一秒钟内开发自己的东西.例如:

   class Program
    {
        static void Main(string[] args)
        {
            var a = new object();
            var b = new object();
            Console.WriteLine("", a.GetId(), b.GetId());
        }
    }

    public static class MyExtensions
    {
        //this dictionary should use weak key references
        static Dictionary<object, int> d = new Dictionary<object,int>();
        static int gid = 0;

        public static int GetId(this object o)
        {
            if (d.ContainsKey(o)) return d[o];
            return d[o] = gid++;
        }
    }   
Run Code Online (Sandbox Code Playgroud)

您可以选择自己拥有的唯一ID,例如System.Guid.NewGuid(),或者只是整数以便最快地访问.

  • 如果您需要的是"Dispose"错误,那将无济于事,因为这会阻止任何处理. (2认同)
  • 但这将使对象保持活动状态。 (2认同)
  • @MartinLottering 如果他使用 ConditionalWeakTable&lt;object, idType&gt; 会怎么样? (2认同)

小智 6

这个方法怎么样:

将第一个对象中的字段设置为新值.如果第二个对象中的相同字段具有相同的值,则它可能是相同的实例.否则,退出不同.

现在将第一个对象中的字段设置为不同的新值.如果第二个对象中的相同字段已更改为不同的值,则它肯定是同一个实例.

不要忘记在退出时将第一个对象中的字段设置回原始值.

问题?


Tho*_*att 5

可以在 Visual Studio 中创建唯一的对象标识符:在监视窗口中,右键单击对象变量并从上下文菜单中选择“创建对象 ID ”。

不幸的是,这是一个手动步骤,我不相信可以通过代码访问标识符。