5

I need to attach a unique identifier to objects at runtime. The identifier must be unique for the duration of the application. I plan to do this my having a private member variable in the base class of my object model. This variable will be set at object initialization and the value will remain constant for the life of the object. No other object can have the same identifier for the duration of the application.

I can, of course, use a System.Guid, but that costs a 128 bits of storage for each object and I would like to consume fewer resources. I tried using an Int32 and initializing it with the System.Environment.TickCount property, but I don't get enough resolution and some objects wind up having the same value assigned.

The documentation for the TickCounter says that the TickCount property will roll to negative after ~29 and then back to zero in another 29 days. I would happly trade more resolution for a shorter roll over time.

Do I have other options that I don't know about?

Michael J
  • 2,443
  • 2
  • 23
  • 24
  • 3
    What resources are you afraid that using GUIDs will consume excessively? That statement sounds a bit like premature optimization. I would start with a solution that uses GUIDs and only reconsider it if you encounter concrete performance bottlenecks. – John Bledsoe Jan 31 '11 at 18:02
  • I was over thinking the problem. Thank you all for getting me on track. – Michael J Jan 31 '11 at 18:43

4 Answers4

14

I would recommend using an integer value, and auto-incrementing it on assignment. You could use Interlocked.Increment to make this operation thread safe.

Most likely, a 32bit integer will be large enough for this task. I would recommend something like:

private static newObjectId = int.MinValue;

private static int GetNextId()
{
    return Interlocked.Increment(ref newObjectId);
}

You can then use that in your base class for assigning a new, unique identifier.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • Good one. You'd put this in the class for which you needed the ID, and perform the assignment in the constructor(s). – KeithS Jan 31 '11 at 18:24
10

To generate unique ids for objects you could use the aptly named ObjectIDGenerator that we conveniently provide for you:

http://msdn.microsoft.com/en-us/library/system.runtime.serialization.objectidgenerator.aspx

Note that, as the comment points out, the object id generator keeps a reference to the object alive, so it is only suitable for objects that you know are going to survive the life of the application anyway. If you intend to use this thing on more ephemeral objects then it is not a good solution.

You could build your own object ID generator that kept weak references if you wanted; it wouldn't be that difficult.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 2
    Interesting. The doc says that ObjectIDGenerator is inteded for use in serialization for the lifetime of the Formatter that created it, and it works by maintaining a relationship between the IDs and the object addresses. From the description it isn’t clear whether the ObjectIDGenerator’s reference to an object will prevent garbage collection of the object. Do you know if this uses weak references, or if it might be the source of a memory leak when used over the life of a program? – Jeffrey L Whitledge Jan 31 '11 at 20:08
  • 1
    @Jeffrey: Excellent point. Yes, the id generator does keep a ref to the object. It is just a simple hash table internally. – Eric Lippert Jan 31 '11 at 20:42
  • I learned something today ... this is why I like StackOverflow. – Michael J Feb 02 '11 at 13:14
3

Do you need the identifier to be unique across all objects or just within a specific type?

You have a couple of options:

  1. If you aren't overriding Object.GetHashCode(), this will give you a pretty (but not 100%) reliable identifier. Note, though, that (per the docs), this is not guaranteed to be unique. Your chances of hitting a duplicate, though, are pretty low.
  2. If you are (or need 100%), the simplest solution would be to use a private static long lastObjectId in your class. Within the base constructor, use Interlocked.Increment(ref lasObjectId) as the value for the current object.
  3. If you need the identifier to be unique across objects, you can do something similar to 2., but you'll have to use a central class to manage these ID's.
Adam Robinson
  • 182,639
  • 35
  • 285
  • 343
2

If the uniqueness is just for the life of the application, can't you use a 32-bit integer, initialized to zero, and then simply incremented with each object allocation?

There's no need to worry about TickCount or anything like that. The number "2" is unique among numbers; it's as different from "1" and "3" as it is from "1,203,718" if all you're testing for is equality.

Pointy
  • 405,095
  • 59
  • 585
  • 614