|
dev
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Nullable<int>, implementing GetHashCode, and thread safetyimplementors: *blockquote* If two objects of the same type represent the same value, the hash function must return the same constant value for either object. For the best performance, a hash function must generate a random distribution for all input. The hash function must return exactly the same value regardless of any changes that are made to the object. */blockquote* So in a reference type that isn't immutable satisfying the third requirement seems to require caching the hash code the first time it's queried for. This seems like a good place for Nullable<int>. However, if there's a competing requirement for the reference type to be thread-safe, the cached hash code needs to be initially assigned in a thread safe manner. To avoid the thread safety problems with double checked locking, there will be a locking cost associated with initially creating and caching the hash code. To minimize the cost, and since the hash code will be int-sized, it'd be nice to take advantage of the System.Threading.Interlocked class's methods. Hmm, but Interlocked.CompareExchange can't handle the following: Nullable<int> alpha = null; int value = 1; Interlocked.CompareExchange(alpha,value,null); Rats. The nullable type would have seemed cleaner, but boxing an int into an object (below) still works. Is this the best way to go? How bad would the overhead of locking a private instance field and using a nullable type be by comparison? Is there something obvious with Nullable<int> that I'm missing that would support this? Should Interlocked get overrides to handle Nullable<T>? Could such overrides avoid the same overhead that locking a private instance field would face? class Triple<T1, T2, T3> { private Object hashCode; private T1 first; private T2 second; private T3 third; //... public override int GetHashCode(){ if (this.hashCode == null){ int firstHash = (!Object.ReferenceEquals(this.first,null)) ? this.first.GetHashCode() : 0; int secondHash = (!Object.ReferenceEquals(this.second,null)) ? this.second.GetHashCode() : 0; int thirdHash = (!Object.ReferenceEquals(this.third,null)) ? this.third.GetHashCode() : 0; Interlocked.CompareExchange(ref this.hashCode, (Object)(firstHash ^ secondHash ^ thirdHash), null); } return (int) this.hashCode; } //... }
Show quote
"dls" <d**@discussions.microsoft.com> wrote in message If your object has no readonly data and you are not overriding ==, then you news:776406B0-30B1-4C65-9B30-64A6DA73CE74@microsoft.com... > The VS2005 documentation for Object.GetHashCode has three notes to > implementors: > > *blockquote* > If two objects of the same type represent the same value, the hash > function > must return the same constant value for either object. > > For the best performance, a hash function must generate a random > distribution for all input. > > The hash function must return exactly the same value regardless of any > changes that are made to the object. > */blockquote* > > So in a reference type that isn't immutable satisfying the third > requirement > seems to require caching the hash code the first time it's queried for. > This > seems like a good place for Nullable<int>. > > However, if there's a competing requirement for the reference type to be > thread-safe, the cached hash code needs to be initially assigned in a > thread > safe manner. To avoid the thread safety problems with double checked > locking, > there will be a locking cost associated with initially creating and > caching > the hash code. To minimize the cost, and since the hash code will be > int-sized, it'd be nice to take advantage of the > System.Threading.Interlocked > class's methods. > should probably just use the default implentation of Object.GetHashCode(). It has all the requisite guarantees. .. . . > class Triple<T1, T2, T3> In this particular case you might just rely on the GetHashCode for the > { > private T1 first; > private T2 second; > private T3 third; > //.. aggregated types and XOR them together. David |
|||||||||||||||||||||||