tags:

views:

256

answers:

5

So I'm thinking of using a reference type as a key to a .NET Dictionary...

Example:

class MyObj
{
    private int mID;
    public MyObj(int id)
    {
        this.mID = id;
    }
}

// whatever code here
static void Main(string[] args)
{
    Dictionary<MyObj, string> dictionary = new Dictionary<MyObj, string>();
}

My question is, how is the hash generated for custom objects (ie not int, string, bool etc)? I ask because the objects I'm using as keys may change before I need to look up stuff in the Dictionary again. If the hash is generated from the object's address, then I'm probably fine... but if it is generated from some combination of the object's member variables then I'm in trouble.

EDIT:

I should've originally made it clear that I don't care about the equality of the objects in this case... I was merely looking for a fast lookup (I wanted to do a 1-1 association without changing the code of the classes involved).

Thanks

+4  A: 

The hash used is the return value of the .GetHashcode method on the object. By default this essentially a value representing the reference. It is not guaranteed to be unique for an object, and in fact likely won't be in many situations. But the value for a particular reference will not change over the lifetime of the object even if you mutate it. So for this particular sample you will be OK.

In general though, it is a very bad idea to use objects which are not immutable as keys to a Dictionary. It's way too easy to fall into a trap where you override Equals and GetHashcode on an object and break code where the type was formerly used as a key in a Dictionary.

JaredPar
Yes but what does it actually hash?
Polaris878
Answers the title, but not really the question :)
cwap
@Polaris878, I expanded the answer to include more about the value
JaredPar
Thanks Jared, but if I could ask a little bit more... If the hash is using a unique value that represents the reference (that won't change over the life time of the reference) then why not use mutable objects as keys?
Polaris878
@Polaris878: Normally you want to compare keys by *values* rather than *references*, so you'd override Equals/GetHashCode. At that point, mutating the key will change its hash, which screws up dictionaries.
Jon Skeet
+1  A: 

The dictionary will use the GetHashCode method defined on System.Object, which will not change over the object's lifetime regardless of field changes etc. So you won't encounter problems in the scenario you describe.

You can override GetHashCode, and should do so if you override Equals so that objects which are equal also return the same hash code. However, if the type is mutable then you must be aware that if you use the object as a key of a dictionary you will not be able to find it again if it is subsequently altered.

Matt Howells
+1  A: 

The default implementation of the GetHashCode method does not guarantee unique return values for different objects. Furthermore, the .NET Framework does not guarantee the default implementation of the GetHashCode method, and the value it returns will be the same between different versions of the .NET Framework. Consequently, the default implementation of this method must not be used as a unique object identifier for hashing purposes.

http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx

Robin Day
MSDN has been updated since then - it isn't quite as scary now. Still overblown, but not scary.
Jon Skeet
Thanks Mr. Skeet. I've updated my answer to use the correct version. I'm amazed that was the first one that came up in google with "default object gethashcode".
Robin Day
Well both pages are "there", and the old one has probably been referenced more than the new...
Jon Skeet
Note that a hash doesn't have to be unique as far as a Dictionary is concerned, hence why it's okay here. We only care about consistency *within this process*.
Jon Skeet
+4  A: 

The default implementation of GetHashCode/Equals basically deals with identity. You'll always get the same hash back from the same object, and it'll probably be different to other objects (very high probability!).

In other words, if you just want reference identity, you're fine. If you want to use the dictionary treating the keys as values (i.e. using the data within the object, rather than just the object reference itself, to determine the notion of equality) then it's a bad idea to mutate any of the equality-sensitive data within the key after adding it to the dictionary.

The MSDN documentation for object.GetHashCode is a little bit overly scary - basically you shouldn't use it for persistent hashes (i.e. saved between process invocations) but it will be consistent for the same object which is all that's required for it to be a valid hash for a dictionary. While it's not guaranteed to be unique, I don't think you'll run into enough collections to cause a problem.

Jon Skeet
+1  A: 
  1. For CustomObject , derived from objects, the hash code will be generated in beginning of the object and they will remain same throughout its life of its instance. Further more, hash code will never change as values of internal fields/properties will change.

  2. Hashtable/Dictionary will not use GetHashCode as unique identifier but rather it will only use it as "hash buckets". For example string "aaa123" and "aaa456" may have hash as "aaa" and that all objects having same hash "aaa" will be stored in one bucket. Whenever you will insert/retrive an object, Dictionary will always call GetHashCode and determine the bucket to further individual address comparison of objects.

  3. Custom Object as Dictionary key should be taken as if, Dictionary only stores theirs "Reference (addresses or memory pointers)" it doesnt know its contents, and contents of objects change but Reference never change. This also means that if two objects are exact replica of each other, but they are different in memory, your hashtable will not consider them as same because their memory pointers are different.

  4. Best way to guarentee identity equality is to override method "Equals" as following... if you are having any problem.

    class MyObj { private int mID; public MyObj(int id) { this.mID = id; } public bool override Equals(Object obj) { MyObj mobj = obj as MyObj; if(mobj==null) return false; return this.mID == mobj.mID; } }

(I guess its bug, stackoverflow cant format above code)

Akash Kava
You have "if(mobj==null) return mobj;" in your Equals() method which has to return a bool!
rstevens
Thanks, fixed it..
Akash Kava