GetHashCode() problem using xor - c#

My understanding is that you're typically supposed to use xor with GetHashCode() to produce an int to identify your data by its value (as opposed to by its reference). Here's a simple example:
class Foo
{
int m_a;
int m_b;
public int A
{
get { return m_a; }
set { m_a = value; }
}
public int B
{
get { return m_b; }
set { m_b = value; }
}
public Foo(int a, int b)
{
m_a = a;
m_b = b;
}
public override int GetHashCode()
{
return A ^ B;
}
public override bool Equals(object obj)
{
return this.GetHashCode() == obj.GetHashCode();
}
}
The idea being, I want to compare one instance of Foo to another based on the value of properties A and B. If Foo1.A == Foo2.A and Foo1.B == Foo2.B, then we have equality.
Here's the problem:
Foo one = new Foo(1, 2);
Foo two = new Foo(2, 1);
if (one.Equals(two)) { ... } // This is true!
These both produce a value of 3 for GetHashCode(), causing Equals() to return true. Obviously, this is a trivial example, and with only two properties I could simply compare the individual properties in the Equals() method. However, with a more complex class this would get out of hand quickly.
I know that sometimes it makes good sense to set the hash code only once, and always return the same value. However, for mutable objects where an evaluation of equality is necessary, I don't think this is reasonable.
What's the best way to handle property values that could easily be interchanged when implementing GetHashCode()?
See Also
What is the best algorithm for an overridden System.Object.GetHashCode?

First off - Do not implement Equals() only in terms of GetHashCode() - hashcodes will sometimes collide even when objects are not equal.
The contract for GetHashCode() includes the following:
different hashcodes means that objects are definitely not equal
same hashcodes means objects might be equal (but possibly might not)
Andrew Hare suggested I incorporate his answer:
I would recommend that you read this solution (by our very own Jon Skeet, by the way) for a "better" way to calculate a hashcode.
No, the above is relatively slow and
doesn't help a lot. Some people use
XOR (eg a ^ b ^ c) but I prefer the
kind of method shown in Josh Bloch's
"Effective Java":
public override int GetHashCode()
{
int hash = 23;
hash = hash*37 + craneCounterweightID;
hash = hash*37 + trailerID;
hash = hash*37 + craneConfigurationTypeCode.GetHashCode();
return hash;
}
The 23 and 37 are arbitrary numbers
which are co-prime.
The benefit of the above over the XOR
method is that if you have a type
which has two values which are
frequently the same, XORing those
values will always give the same
result (0) whereas the above will
differentiate between them unless
you're very unlucky.
As mentioned in the above snippet, you might also want to look at Joshua Bloch's book, Effective Java, which contains a nice treatment of the subject (the hashcode discussion applies to .NET as well).

Andrew has posted a good example for generating a better hash code, but also bear in mind that you shouldn't use hash codes as an equality check, since they are not guaranteed to be unique.
For a trivial example of why this is consider a double object. It has more possible values than an int so it is impossible to have a unique int for each double. Hashes are really just a first pass, used in situations like a dictionary when you need to find the key quickly, by first comparing hashes a large percentage of the possible keys can be ruled out and only the keys with matching hashes need to have the expense of a full equality check (or other collision resolution methods).

Hashing always involves collisions and you have to deal with it (f.e., compare hash values and if they are equal, exactly compare the values inside the classes to be sure the classes are equal).
Using a simple XOR, you'll get many collisions. If you want less, use some mathematical functions that distribute values across different bits (bit shifts, multiplying with primes etc.).

Read Overriding GetHashCode for mutable objects? C# and think about implementing IEquatable<T>

There are several better hash implementations. FNV hash for example.

Out of curiosity since hashcodes are typically a bad idea for comparison, wouldn't it be better to just do the following code, or am I missing something?
public override bool Equals(object obj)
{
bool isEqual = false;
Foo otherFoo = obj as Foo;
if (otherFoo != null)
{
isEqual = (this.A == otherFoo.A) && (this.B == otherFoo.B);
}
return isEqual;
}

A quick generate and good distribution of hash
public override int GetHashCode()
{
return A.GetHashCode() ^ B.GetHashCode(); // XOR
}

Related

How to implement GetHashcode for a difference-tolerant DateTime comparer? [duplicate]

I am trying to implement an IEqualityComparer that has a tolerance on a date comparison. I have also looked into this question. The problem is that I can't use a workaround because I am using the IEqualityComparer in a LINQ .GroupJoin(). I have tried a few implementations that allow for tolerance. I can get the Equals() to work because I have both objects but I can't figure out how to implement GetHashCode().
My best attempt looks something like this:
public class ThingWithDateComparer : IEqualityComparer<IThingWithDate>
{
private readonly int _daysToAdd;
public ThingWithDateComparer(int daysToAdd)
{
_daysToAdd = daysToAdd;
}
public int GetHashCode(IThingWithDate obj)
{
unchecked
{
var hash = 17;
hash = hash * 23 + obj.BirthDate.AddDays(_daysToAdd).GetHashCode();
return hash;
}
}
public bool Equals(IThingWithDate x, IThingWithDate y)
{
throw new NotImplementedException();
}
}
public interface IThingWithDate
{
DateTime BirthDate { get; set; }
}
With .GroupJoin() building a HashTable out of the GetHashCode() it applies the days to add to both/all objects. This doesn't work.
The problem is impossible, conceptually. You're trying to compare objects in a way that doesn't have a form of equality that is necessary for the operations you're trying to perform with it. For example, GroupJoin is dependant on the assumption that if A is equal to B, and B is equal to C, then A is equal to C, but in your situation, that's not true. A and B may be "close enough" together for you to want to group them, but A and C may not be.
You're going to need to not implement IEqualityComparer at all, because you cannot fulfill the contract that it requires. If you want to create a mapping of items in one collection to all of the items in another collection that are "close enough" to it then you're going to need to write that algorithm yourself (doing so efficiently is likely to be hard, but doing so inefficiently isn't shouldn't' be that difficult), rather than using GroupJoin, because it's not capable of performing that operation.
I can't see any way to generate a logical hash code for your given criteria.
The hash code is used to determine if 2 dates should stick together. If they should group together, than they must return the same hash code.
If your "float" is 5 days, that means that 1/1/2000 must generate the same hash code as 1/4/2000, and 1/4/2000 must generate the same hashcode as 1/8/2000 (since they are both within 5 days of each other). That implies that 1/1/2000 has the same code as 1/8/2000 (since if a=b and b=c, a=c).
1/1/2000 and 1/8/2000 are outside the 5 day "float".

Understanding behavior & overriding GetHashCode()

I tried to followed the Guidelines from MSDN and also referred to This great question but the following seems to not behave as expected.
I'm trying to represent a structure similar to a FQN where as if P1 was listed before P2, P2 would only exist in the same set as P1. Like how scope works.
On the subject of GetHashCode()
I have a class with properties like this.
class data{
public readonly string p1, p2;
public data(string p1, string p2) {
this.p1 = p1;
this.p2 = p2;
}
public override int GetHashCode()
{
return this.p1.GetHashCode() ^ this.p2.GetHashCode();
}
/*also show the equal for comparison*/
public override bool Equals(System.Object obj)
{
if (obj == null)
return false;
data d = obj as data;
if ((System.Object)d == null)
return false;
/*I thought this would be smart*/
return d.ToString() == this.ToString();
}
public override string ToString() {
return "[" + p1 +"][" + p2+ "]";
}
}
In a Dictionary (dict) I use data as a key, so this would make the scope look like d1.p1.p2 (or rather p2 of p1 of d1, however you prefer to imagine it)
Dictionary<data,int> dict = new Dictionary<data,int>();
I've examined the behavior when d1.p1 and another d2.p1 are different, the operation resolves correctly. However when d1.p1 and d2.p1 are the same and p2 of d1 and d2 are different I observe the following behavior.
data d1 = new data(){ p1="p1", p2="p2" };
data d2 = new data(){ p1="p1", p2="XX" };
dict.add(d1, 0);
dict.add(d2, 1);
dict[d1] = 4;
The result is that both elements are 4
Is GetHashCode() overridden correctly?
Is Equals overridden correctly?
If they are both fine how/why does this behavior happen?
On the subject of a Dictionary
In the watch window (VS2013), I have my dictionary's key list show me, instead of a single key per index as I would normally expect, each property of my data object is a key for a single index. So I'm not sure if in there lay the problem or I'm just misunderstanding the Watch window's representation of an object as a key. I know how that is the way VS will display an object but, I'm not certain that's how I would expect it to be displayed for a key in a dictionary.
I thought GetHashCode() was a Dictionary's primary "comparison" operation, is this always correct?
What's the real "Index" to a Dictionary where the key is an object?
UPDATE
After looking at each hash code directly I noticed that they do repeat. Yet the Dictionary does not determine that the index exists. Below is an example of the data I see.
1132917379 string: [ABC][ABC]
-565659420 string: [ABC][123]
-1936108909 string: [123][123]
//second loop with next set of strings
1132917379 string: [xxx][xxx]
-565659420 string: [xxx][yyy]
//...etc
Is GetHachCode() overridden correctly?
Sure, for some definition of "correct". It may not be overridden well, but it's not an incorrect implementation (since two instances of the class that are considered equal will hash to the same value). Of course with that requirement you could always just return 0 from GetHashCode and it would be "correct". It certainly wouldn't be good.
That said your particular implementation is not as good as it could be. For example, in your class, the order of the strings matter. I.e. new data( "A", "B" ) != new data( "B", "A" ). However, these will always hash equal because your GetHashCode implementation is symmetric. Better to break the symmetry in some fashion. For example:
public int GetHashCode()
{
return p1.GetHashCode() ^ ( 13 * p2.GetHashCode() );
}
Now it's less likely that there will be a collision for two instances that are not equal.
Is Equal overridden correctly?
Well, it can definitely be improved. For example, the first null check is redundant and so is the cast to object in the second comparison. The whole thing would probably be better written as:
public bool Equals( object obj )
{
var other = obj as data;
if( other == null ) return false;
return p1 == obj.p1 && p2 == obj.p2;
}
I also removed the call to ToString since it doesn't significantly simplify the code or make it more readable. It's also an inefficient way of performing the comparison, since you have to construct two new strings before the comparison even happens. Just comparing the members directly gives you more opportunities for an early out and, more importantly, is a lot easier to read (the actual equality implementation doesn't depend on the string representation).
If they are both fine how/why does this behavior happen?
I don't know, because the code you've given won't do this. It also won't compile. Your data class has two readonly fields, you can't assign those using an initializer list as you've shown in your last code snippet.
I can only speculate as to the behavior you're seeing, because nothing you've shown here would result in the behavior as described.
The best advice I can give is to make sure that your key class is not mutable. Mutable types will not play nice with Dictionary. The Dictionary class does not expect the hash codes of objects to change, so if GetHashCode depends on any part of your class that is mutable, it's very possible for things to get very messed up.
I thought GetHachCode() was a Dictionary's primary "comparison" operation, is this always correct?
Dictionary only uses GetHashCode as a way to "address" objects (to be specific the hash code is used to identify which bucket an item should be placed in). It doesn't use it directly as a comparison necessarily. And if it does, it can only use it to determine that two objects are not equal, it can't use it to determine if they are equal.
What's the real "Index" to a Dictionary where the key is an object?
I'm not entirely sure what you're asking here, but I'm inclined to say that the answer is that it doesn't matter. Where the item goes is unimportant. If you care about that sort of thing, you probably shouldn't be using a Dictionary.
Is GetHashCode() overridden correctly?
No. You allow passing null for p1 or p2 and null.GetHashCode() throws a NullReferenceException which is not allowed in GetHashCode. Either forbid passing null, or make GetHashCode return an int for nulls (zero is OK).
You are also XORing unaltered ints; this means every class you create that contain two of the same values will have a hashCode of zero. This is a very common collision; typically one multiplies each hashcode by a prime number to avoid this.
Is Equals overridden correctly?
No. The page you linked to is the non-generic Equals used by System.Collections.HashTable. You are using the generic System.Collections.Generic.Dictionary, which uses the generic IEquatable<T>. You need to implement IEquatable<data> as explained in the accepted answer to the SO question you posted.
It is true that IEquatable<data> will fall back to Equals(System.Object obj) if not defined, but do not rely on that behavior. Also, converting ints to strings to compare them is not “smart”. Any time you feel you should write a comment excusing something as “smart” you are making a mistake.
A better implementation of 'data` would be:
public class MatPair : IEquatable<MatPair>
{
public readonly string MatNeedsToExplainWhatThisRepresents;
public readonly string MatNeedsToExplainThisToo;
public MatPair(string matNeedsToExplainWhatThisRepresents,
string matNeedsToExplainThisToo)
{
if (matNeedsToExplainWhatThisRepresents == null) throw new ArgumentNullException("matNeedsToExplainWhatThisRepresents");
if (matNeedsToExplainThisToo == null) throw new ArgumentNullException("matNeedsToExplainThisToo");
this.MatNeedsToExplainWhatThisRepresents = matNeedsToExplainWhatThisRepresents;
this.MatNeedsToExplainThisToo = matNeedsToExplainThisToo;
}
[Obsolete]
public override bool Equals(object obj)
{
return Equals(obj as MatPair);
}
public bool Equals(MatPair matPair)
{
return matPair != null
&& matPair.MatNeedsToExplainWhatThisRepresents == MatNeedsToExplainWhatThisRepresents
&& matPair.MatNeedsToExplainThisToo == MatNeedsToExplainThisToo;
}
public override int GetHashCode()
{
unchecked
{
return MatNeedsToExplainWhatThisRepresents.GetHashCode() * 31
^ MatNeedsToExplainThisToo.GetHashCode();
}
}
public override string ToString()
{
return "{" + MatNeedsToExplainWhatThisRepresents + ", "
+ MatNeedsToExplainThisToo + "}";
}
}

How to reduce complexity of GetHashCode

I want to decrease my code execution time. Looking at some testing results, I found out that GetHashCode() took 21,62% of my execution time.
I also got a warning:
Warning 1 DA0010: .*.GetHashCode() = 7,63; GetHashCode functions
should be cheap and not allocate any memory. Reduce complexity of hash
code function if possible.
Code Snippets:
My GetHashCode() in Field Class:
public override int GetHashCode()
{
int hash = 7;
hash = (hash * 13) + this.Coordinate.GetHashCode();
return hash;
}
My GetHashCode() in Coordinate Class:
public override int GetHashCode()
{
int hash = 17;
hash = (hash * 23) + this.Row.GetHashCode();
hash = (hash * 23) + this.Column.GetHashCode();
return hash;
}
Edit: Row and Column are just byte variables. I just call their property which returns a byte in the get accessor
My GetHashCode() in Sudoku Class:
public override int GetHashCode()
{
int hash = 7;
hash = (hash * 5) + this.Grid.GetHashCode();
return hash;
}
Edit: Grid is just a multidimensional array of type: Field[,], I just call it's Property here which returns a Field[,] grid through it's get accessor.
Questions: How can I greatly decrease the complexity of my GetHashCode() and increase it's performance? Why is the performance of GetHashCode() method so low?
I suspect you'll find that GetHashCode isn't your problem. If you're spending > 20% of your time in GetHashCode, you must be doing a whole lot of dictionary lookups. Or you're using the hash code for something you probably shouldn't be using it for.
GetHashCode might be the manifestation of the performance problem, but it's almost certainly not the cause.
Your calculation is just adding a conts to your hashcode. Only the combination of your hashcodes needs to have a better hashcode then just adding the two values:
//Field
public override int GetHashCode()
{
return this.Coordinate.GetHashCode();
}
//Coordinate
public override int GetHashCode()
{
return this.Column.GetHashCode() * 17 + this.Row.GetHashCode();
}
//Sudoku, I doubt if this is ever called...
public override int GetHashCode()
{
return this.Grid.GetHashCode();
}
For performance it realy depends on how often you call GetHashCode (if you do any calculation). Or if you store them in some kind of dictionay, the problem can be multiple values with the same hash, which will decrese your access time to the objects in the dictionary/hashtable. So your hashfunction has to be a good distrubution for the set you are storing.
If your classes don't have too many mutators, you can cache the hash code and just return the cached value from GetHashCode(). (Even if you have a lot of mutators you can do this, but it is likely to be much less effective if objects are frequently mutated.)
You should lazily evaluate it. You will need to know when it is dirty and needs to be recalculated. You can do this easily by adding a bool isHashCodeDirty field, which is initialised to true when the class is constructed and also by every mutator method.
Then in your implementation of GetHashCode() if isHashCodeDirty is true, set it to false and recalculate and return the hash code. If it's false, just return the cached value.
You have to be careful with multithreading here, of course. I think that adding a lock to GetHashCode() would impact performance quite a lot though!
The ideal of course is to have immutable classes; then you just calculate the hash code once in the constructor and it'll never change thereafter.
Looks like the problem is not in integer addition, but in accessing properties like this.Coordinate, this.Grid, e.t.c.
Take a look at their get accessors, they may be doing some extra work.

Why is it important to override GetHashCode when Equals method is overridden?

Given the following class
public class Foo
{
public int FooId { get; set; }
public string FooName { get; set; }
public override bool Equals(object obj)
{
Foo fooItem = obj as Foo;
if (fooItem == null)
{
return false;
}
return fooItem.FooId == this.FooId;
}
public override int GetHashCode()
{
// Which is preferred?
return base.GetHashCode();
//return this.FooId.GetHashCode();
}
}
I have overridden the Equals method because Foo represent a row for the Foos table. Which is the preferred method for overriding the GetHashCode?
Why is it important to override GetHashCode?
Yes, it is important if your item will be used as a key in a dictionary, or HashSet<T>, etc - since this is used (in the absence of a custom IEqualityComparer<T>) to group items into buckets. If the hash-code for two items does not match, they may never be considered equal (Equals will simply never be called).
The GetHashCode() method should reflect the Equals logic; the rules are:
if two things are equal (Equals(...) == true) then they must return the same value for GetHashCode()
if the GetHashCode() is equal, it is not necessary for them to be the same; this is a collision, and Equals will be called to see if it is a real equality or not.
In this case, it looks like "return FooId;" is a suitable GetHashCode() implementation. If you are testing multiple properties, it is common to combine them using code like below, to reduce diagonal collisions (i.e. so that new Foo(3,5) has a different hash-code to new Foo(5,3)):
In modern frameworks, the HashCode type has methods to help you create a hashcode from multiple values; on older frameworks, you'd need to go without, so something like:
unchecked // only needed if you're compiling with arithmetic checks enabled
{ // (the default compiler behaviour is *disabled*, so most folks won't need this)
int hash = 13;
hash = (hash * 7) + field1.GetHashCode();
hash = (hash * 7) + field2.GetHashCode();
...
return hash;
}
Oh - for convenience, you might also consider providing == and != operators when overriding Equals and GetHashCode.
A demonstration of what happens when you get this wrong is here.
It's actually very hard to implement GetHashCode() correctly because, in addition to the rules Marc already mentioned, the hash code should not change during the lifetime of an object. Therefore the fields which are used to calculate the hash code must be immutable.
I finally found a solution to this problem when I was working with NHibernate.
My approach is to calculate the hash code from the ID of the object. The ID can only be set though the constructor so if you want to change the ID, which is very unlikely, you have to create a new object which has a new ID and therefore a new hash code. This approach works best with GUIDs because you can provide a parameterless constructor which randomly generates an ID.
By overriding Equals you're basically stating that you know better how to compare two instances of a given type.
Below you can see an example of how ReSharper writes a GetHashCode() function for you. Note that this snippet is meant to be tweaked by the programmer:
public override int GetHashCode()
{
unchecked
{
var result = 0;
result = (result * 397) ^ m_someVar1;
result = (result * 397) ^ m_someVar2;
result = (result * 397) ^ m_someVar3;
result = (result * 397) ^ m_someVar4;
return result;
}
}
As you can see it just tries to guess a good hash code based on all the fields in the class, but if you know your object's domain or value ranges you could still provide a better one.
Please don´t forget to check the obj parameter against null when overriding Equals().
And also compare the type.
public override bool Equals(object obj)
{
Foo fooItem = obj as Foo;
if (fooItem == null)
{
return false;
}
return fooItem.FooId == this.FooId;
}
The reason for this is: Equals must return false on comparison to null. See also http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx
How about:
public override int GetHashCode()
{
return string.Format("{0}_{1}_{2}", prop1, prop2, prop3).GetHashCode();
}
Assuming performance is not an issue :)
As of .NET 4.7 the preferred method of overriding GetHashCode() is shown below. If targeting older .NET versions, include the System.ValueTuple nuget package.
// C# 7.0+
public override int GetHashCode() => (FooId, FooName).GetHashCode();
In terms of performance, this method will outperform most composite hash code implementations. The ValueTuple is a struct so there won't be any garbage, and the underlying algorithm is as fast as it gets.
Just to add on above answers:
If you don't override Equals then the default behavior is that references of the objects are compared. The same applies to hashcode - the default implmentation is typically based on a memory address of the reference.
Because you did override Equals it means the correct behavior is to compare whatever you implemented on Equals and not the references, so you should do the same for the hashcode.
Clients of your class will expect the hashcode to have similar logic to the equals method, for example linq methods which use a IEqualityComparer first compare the hashcodes and only if they're equal they'll compare the Equals() method which might be more expensive to run, if we didn't implement hashcode, equal object will probably have different hashcodes (because they have different memory address) and will be determined wrongly as not equal (Equals() won't even hit).
In addition, except the problem that you might not be able to find your object if you used it in a dictionary (because it was inserted by one hashcode and when you look for it the default hashcode will probably be different and again the Equals() won't even be called, like Marc Gravell explains in his answer, you also introduce a violation of the dictionary or hashset concept which should not allow identical keys -
you already declared that those objects are essentially the same when you overrode Equals so you don't want both of them as different keys on a data structure which suppose to have a unique key. But because they have a different hashcode the "same" key will be inserted as different one.
It is because the framework requires that two objects that are the same must have the same hashcode. If you override the equals method to do a special comparison of two objects and the two objects are considered the same by the method, then the hash code of the two objects must also be the same. (Dictionaries and Hashtables rely on this principle).
We have two problems to cope with.
You cannot provide a sensible GetHashCode() if any field in the
object can be changed. Also often a object will NEVER be used in a
collection that depends on GetHashCode(). So the cost of
implementing GetHashCode() is often not worth it, or it is not
possible.
If someone puts your object in a collection that calls
GetHashCode() and you have overrided Equals() without also making
GetHashCode() behave in a correct way, that person may spend days
tracking down the problem.
Therefore by default I do.
public class Foo
{
public int FooId { get; set; }
public string FooName { get; set; }
public override bool Equals(object obj)
{
Foo fooItem = obj as Foo;
if (fooItem == null)
{
return false;
}
return fooItem.FooId == this.FooId;
}
public override int GetHashCode()
{
// Some comment to explain if there is a real problem with providing GetHashCode()
// or if I just don't see a need for it for the given class
throw new Exception("Sorry I don't know what GetHashCode should do for this class");
}
}
Hash code is used for hash-based collections like Dictionary, Hashtable, HashSet etc. The purpose of this code is to very quickly pre-sort specific object by putting it into specific group (bucket). This pre-sorting helps tremendously in finding this object when you need to retrieve it back from hash-collection because code has to search for your object in just one bucket instead of in all objects it contains. The better distribution of hash codes (better uniqueness) the faster retrieval. In ideal situation where each object has a unique hash code, finding it is an O(1) operation. In most cases it approaches O(1).
It's not necessarily important; it depends on the size of your collections and your performance requirements and whether your class will be used in a library where you may not know the performance requirements. I frequently know my collection sizes are not very large and my time is more valuable than a few microseconds of performance gained by creating a perfect hash code; so (to get rid of the annoying warning by the compiler) I simply use:
public override int GetHashCode()
{
return base.GetHashCode();
}
(Of course I could use a #pragma to turn off the warning as well but I prefer this way.)
When you are in the position that you do need the performance than all of the issues mentioned by others here apply, of course. Most important - otherwise you will get wrong results when retrieving items from a hash set or dictionary: the hash code must not vary with the life time of an object (more accurately, during the time whenever the hash code is needed, such as while being a key in a dictionary): for example, the following is wrong as Value is public and so can be changed externally to the class during the life time of the instance, so you must not use it as the basis for the hash code:
class A
{
public int Value;
public override int GetHashCode()
{
return Value.GetHashCode(); //WRONG! Value is not constant during the instance's life time
}
}
On the other hand, if Value can't be changed it's ok to use:
class A
{
public readonly int Value;
public override int GetHashCode()
{
return Value.GetHashCode(); //OK Value is read-only and can't be changed during the instance's life time
}
}
You should always guarantee that if two objects are equal, as defined by Equals(), they should return the same hash code. As some of the other comments state, in theory this is not mandatory if the object will never be used in a hash based container like HashSet or Dictionary. I would advice you to always follow this rule though. The reason is simply because it is way too easy for someone to change a collection from one type to another with the good intention of actually improving the performance or just conveying the code semantics in a better way.
For example, suppose we keep some objects in a List. Sometime later someone actually realizes that a HashSet is a much better alternative because of the better search characteristics for example. This is when we can get into trouble. List would internally use the default equality comparer for the type which means Equals in your case while HashSet makes use of GetHashCode(). If the two behave differently, so will your program. And bear in mind that such issues are not the easiest to troubleshoot.
I've summarized this behavior with some other GetHashCode() pitfalls in a blog post where you can find further examples and explanations.
As of C# 9(.net 5 or .net core 3.1), you may want to use records as it does Value Based Equality by default.
It's my understanding that the original GetHashCode() returns the memory address of the object, so it's essential to override it if you wish to compare two different objects.
EDITED:
That was incorrect, the original GetHashCode() method cannot assure the equality of 2 values. Though objects that are equal return the same hash code.
Below using reflection seems to me a better option considering public properties as with this you don't have have to worry about addition / removal of properties (although not so common scenario). This I found to be performing better also.(Compared time using Diagonistics stop watch).
public int getHashCode()
{
PropertyInfo[] theProperties = this.GetType().GetProperties();
int hash = 31;
foreach (PropertyInfo info in theProperties)
{
if (info != null)
{
var value = info.GetValue(this,null);
if(value != null)
unchecked
{
hash = 29 * hash ^ value.GetHashCode();
}
}
}
return hash;
}

How do you implement GetHashCode for structure with two string, when both strings are interchangeable

I have a structure in C#:
public struct UserInfo
{
public string str1
{
get;
set;
}
public string str2
{
get;
set;
}
}
The only rule is that UserInfo(str1="AA", str2="BB").Equals(UserInfo(str1="BB", str2="AA"))
How to override the GetHashCode function for this structure?
MSDN:
A hash function must have the following properties:
If two objects compare as equal, the GetHashCode method for each object must return the same value. However, if two objects do not compare as equal, the GetHashCode methods for the two object do not have to return different values.
The GetHashCode method for an object must consistently return the same hash code as long as there is no modification to the object state that determines the return value of the object's Equals method. Note that this is true only for the current execution of an application, and that a different hash code can be returned if the application is run again.
For the best performance, a hash function must generate a random distribution for all input.
Taking it into account correct way is:
return str1.GetHashCode() ^ str2.GetHashCode()
^ can be substituted with other commutative operation
See Jon Skeet's answer - binary operations like ^ are not good, they will often generate colliding hash!
public override int GetHashCode()
{
unchecked
{
return (str1 ?? String.Empty).GetHashCode() +
(str2 ?? String.Empty).GetHashCode();
}
}
Using the '+' operator might be better than using '^', because although you explicitly want ('AA', 'BB') and ('BB', 'AA') to explicitly be the same, you may not want ('AA', 'AA') and ('BB', 'BB') to be the same (or all equal pairs for that matter).
The 'as fast as possible' rule is not entirely adhered to in this solution because in the case of nulls this performs a 'GetHashCode()' on the empty string rather than immediately return a known constant, but even without explicitly measuring I am willing to hazard a guess that the difference wouldn't be big enough to worry about unless you expect a lot of nulls.
As a general rule, a simple way to generate a hashcode for a class is to XOR all the data fields that can participate in generating the hash code (being careful to check for null as pointed out by others). This also meets the (artificial?) requirement that the hashcodes for UserInfo("AA", "BB") and UserInfo("BB", "AA") are the same.
If you can make assumptions about the use of your class, you can perhaps improve your hash function. For example, if it is common for str1 and str2 to be the same, XOR may not be a good choice. But if str1 and str2 represent, say, first and last name, XOR is probably a good choice.
Although this is clearly not meant to be a real-world example, it may be worth pointing out that:
- This is probably a poor example of use of a struct: A struct should normally have value semantics, which doesn't seem to be the case here.
- Using properties with setters to generate a hash code is also asking for trouble.
Going along the lines ReSharper is suggesting:
public int GetHashCode()
{
unchecked
{
int hashCode;
// String properties
hashCode = (hashCode * 397) ^ (str1!= null ? str1.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (str2!= null ? str1.GetHashCode() : 0);
// int properties
hashCode = (hashCode * 397) ^ intProperty;
return hashCode;
}
}
397 is a prime of sufficient size to cause the result variable to overflow and mix the bits of the hash somewhat, providing a better distribution of hash codes. Otherwise there's nothing special in 397 that distinguishes it from other primes of the same magnitude.
A simple general way is to do this:
return string.Format("{0}/{1}", str1, str2).GetHashCode();
Unless you have strict performance requirements, this is the easiest I can think of and I frequently use this method when I need a composite key. It handles the null cases just fine and won't cause (m)any hash collisions (in general). If you expect '/' in your strings, just choose another separator that you don't expect.
public override int GetHashCode()
{
unchecked
{
return(str1 != null ? str1.GetHashCode() : 0) ^ (str2 != null ? str2.GetHashCode() : 0);
}
}
Ah yes, as Gary Shutler pointed out:
return str1.GetHashCode() + str2.GetHashCode();
Can overflow. You could try casting to long as Artem suggested, or you could surround the statement in the unchecked keyword:
return unchecked(str1.GetHashCode() + str2.GetHashCode());
Try out this one:
(((long)str1.GetHashCode()) + ((long)str2.GetHashCode())).GetHashCode()
Since C# 7, we can take advantage of ValueTuple for that:
return (str1, str2).GetHashCode();
Many possibilities. E.g.
return str1.GetHashCode() ^ str1.GetHashCode()
Perhaps something like str1.GetHashCode() + str2.GetHashCode()? or (str1.GetHashCode() + str2.GetHashCode()) / 2? This way it would be the same regardless of whether str1 and str2 are swapped....
Sort them, then concatenate them:
return ((str1.CompareTo(str2) < 1) ? str1 + str2 : str2 + str1)
.GetHashCode();
GetHashCode's result is supposed to be:
As fast as possible.
As unique as possible.
Bearing those in mind, I would go with something like this:
if (str1 == null)
if (str2 == null)
return 0;
else
return str2.GetHashCode();
else
if (str2 == null)
return str1.GetHashCode();
else
return ((ulong)str1.GetHashCode() | ((ulong)str2.GetHashCode() << 32)).GetHashCode();
Edit: Forgot the nulls. Code fixed.
Too complicated, and forgets nulls, etc. This is used for things like bucketing, so you can get away with something like
if (null != str1) {
return str1.GetHashCode();
}
if (null != str2) {
return str2.GetHashCode();
}
//Not sure what you would put here, some constant value will do
return 0;
This is biased by assuming that str1 is not likely to be common in an unusually large proportion of instances.

Categories

Resources