G
Guest
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.
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;
}
//...
}
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.
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;
}
//...
}