.NET unique object identifier
.NET 4 and later only
Good news, everyone!
The perfect tool for this job is built in .NET 4 and it's called ConditionalWeakTable<TKey, TValue>
. This class:
- can be used to associate arbitrary data with managed object instances much like a dictionary (although it is not a dictionary)
- does not depend on memory addresses, so is immune to the GC compacting the heap
- does not keep objects alive just because they have been entered as keys into the table, so it can be used without making every object in your process live forever
- uses reference equality to determine object identity; moveover, class authors cannot modify this behavior so it can be used consistently on objects of any type
- can be populated on the fly, so does not require that you inject code inside object constructors
The reference is the unique identifier for the object. I don't know of any way of converting this into anything like a string etc. The value of the reference will change during compaction (as you've seen), but every previous value A will be changed to value B, so as far as safe code is concerned it's still a unique ID.
If the objects involved are under your control, you could create a mapping using weak references (to avoid preventing garbage collection) from a reference to an ID of your choosing (GUID, integer, whatever). That would add a certain amount of overhead and complexity, however.
Checked out the ObjectIDGenerator class? This does what you're attempting to do, and what Marc Gravell describes.
The ObjectIDGenerator keeps track of previously identified objects. When you ask for the ID of an object, the ObjectIDGenerator knows whether to return the existing ID, or generate and remember a new ID.
The IDs are unique for the life of the ObjectIDGenerator instance. Generally, a ObjectIDGenerator life lasts as long as the Formatter that created it. Object IDs have meaning only within a given serialized stream, and are used for tracking which objects have references to others within the serialized object graph.
Using a hash table, the ObjectIDGenerator retains which ID is assigned to which object. The object references, which uniquely identify each object, are addresses in the runtime garbage-collected heap. Object reference values can change during serialization, but the table is updated automatically so the information is correct.
Object IDs are 64-bit numbers. Allocation starts from one, so zero is never a valid object ID. A formatter can choose a zero value to represent an object reference whose value is a null reference (Nothing in Visual Basic).