views:

146

answers:

4

I am doing some diagnostic logging with one of my C#.NET projects and I would like to be able to log an identifier that represents a specific instance of a class. I know I could do this with a static variable that just gets incremented every time a class instance is created but I am just wondering if there is any built-in way in the .NET framework to do this. Maybe using reflection or something.

+3  A: 

The closest thing is GetHashCode(), but that is not guaranteed to be unique. It would usually be sufficient for diagnostics though.

I just read the answers to this similar question. According to JS there is the overhead of allocating a syncblock for the 1st call to GethashCode. That might be a problem.

Henk Holterman
Does GetHashcode change from instance to instance? It should not change if the objects equal each other.
Zebi
Two instances of the same class initialized with the same values would have to return the same hash code, so this really wouldn't work at all.
Jon B
@Jon B: That is only true for some classes (like string) that override GethashCode(). The default version is part of System.Object and can't see your members. Try it.
Henk Holterman
@Henk - Ah, I misunderstood. I thought you were suggesting he implement GetHashCode() and use it. (Edited to allow me to un-downvote)
Jon B
@Zebi: Different HashCodes is guaranteed to mean different instances. The same HashCode has a tiny chance of being from 2 different instances. For an ideal Hash function it is 1 in 4E9. You can safely assume the chance of a 'collision' is less than 1 in a million.
Henk Holterman
So an single instance of a class will always return the same HashCode?
Jordan S
If you are overriding equality members it is encouraged to implement GetHashCode yourself. If you are using objects from frameworks which implemented GetHashCode and equality you may end up with **different codes for a single instance**. The code will change if a property or any field used to determine equality changes.
Zebi
@Jordan, In practice: Yes. It is theoretically possible to create a class where this doesn't hold, but that class would be breaking all the guidelines.
Henk Holterman
@Zebi: You are also encouraged to make such a class immutable. And the problem doesn't come up.
Henk Holterman
A: 

Maybe Object.ReferenceEquals solves your problem. At least it can tell you if an object is the same as some other.

You can not use a static variable because it will be the same in each instance. It will just have the count of the objects created.

You have the possibility to use Jon B's solution or if you want numeric identifiers use a static counter and assign an id to a field.

public class Foo
{
    static int counter;
    public int InstanceId;

    public Foo()
    {
        InstanceId = counter++;
    }
}
Zebi
I'm pretty sure what you describe in your last part is exactly what the OP meant by "static variable" (that would be `counter`).
Dan Tao
+5  A: 

You could add a Guid property to your class an initialize it in the constructor (guaranteed unique for each instance).

Jon B
Used this technique a few times. You can just directly initialize a field `public Guid InstanceId = Guid.NewGuid();` to keep your constructor clean of debugging stuff.
Zebi
That is not much easier or any more convenient than using a static counter. It is a lot harder on the eyes.
Henk Holterman
How would you use a static counter? It will be the same in each instance since it is static. Am I mistaken?
Zebi
@Zebi - `static int s_counter = 0;` and then `int id = s_counter++;`. Each object will be sequentially numbered with no repeats.
Jon B
@Zebi, @Henk - Using a `Guid` is only a tiny bit easier, but as Henk said, it's harder to read. The only advantage here is that a `Guid` is unique across all objects, not just instances of the same class. Of course, you could create a static counter for that, too, if you really wanted to.
Jon B
@Henk's solution is probably the easiest, even though it's not "technically" perfect. I only posted this before I understood he meant to use the default `GetHashcode()` behavior.
Jon B
+3  A: 

Just to add to what Henk said in his answer about GetHashCode, and to mitigate some of the negative comments he received on that answer:

There is a way to call GetHashCode on any object that is independent of that object's value, regardless of whether or not its type has overridden GetHashCode.

Take a look at System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode.

This value is not guaranteed to be unique, of course. Neither is a Guid (though for that not to be unique would involve odds that are legitimately microscopic).

I'd say your gut was right about the static counter variable. I should mention, though, that simply incrementing it using the ++ operator in each object's constructor is not thread-safe. If it's possible you could be instantiating instances of a class from multiple threads you would want to use Interlocked.Increment instead.

Dan Tao
Interesting link.
Henk Holterman