Question about the dictionary <T, T>

I have a class that looks like this:

public class NumericalRange:IEquatable<NumericalRange> { public double LowerLimit; public double UpperLimit; public NumericalRange(double lower, double upper) { LowerLimit = lower; UpperLimit = upper; } public bool DoesLieInRange(double n) { if (LowerLimit <= n && n <= UpperLimit) return true; else return false; } #region IEquatable<NumericalRange> Members public bool Equals(NumericalRange other) { if (Double.IsNaN(this.LowerLimit)&& Double.IsNaN(other.LowerLimit)) { if (Double.IsNaN(this.UpperLimit) && Double.IsNaN(other.UpperLimit)) { return true; } } if (this.LowerLimit == other.LowerLimit && this.UpperLimit == other.UpperLimit) return true; return false; } #endregion } 

This class contains a non-periodic range of values. This class should also have a range of default values, where both LowerLimit and UpperLimit are Double.NaN.

Now this class goes into the dictionary

The dictionary works fine for non-NaN range values, but when the key is {NaN, NaN} NumericalRange Object, then the dictionary throws a KeyNotFoundException.

What am I doing wrong? Is there any other interface I have to implement?

+4
source share
2 answers

Based on your comment, you did not implement GetHashCode. I am amazed that the class works in general in the dictionary, if you do not always request the identical key that you insert. I would suggest an implementation of something like:

 public override int GetHashCode() { int hash = 17; hash = hash * 23 + UpperLimit.GetHashCode(); hash = hash * 23 + LowerLimit.GetHashCode(); return hash; } 

This assumes Double.GetHashCode() gives a consistent value for NaN. Of course, there are many NaN values, and you might need a special case to make sure that they all give the same hash.

You must also override the Equals method inherited from Object :

 public override bool Equals(Object other) { return other != null && other.GetType() == GetType() && Equals((NumericalRange) other); } 

Note that type checking can be more efficient with as if you close your class. Otherwise, you get interesting asymmetries between x.Equals(y) and y.Equals(x) if someone gets a different class from yours. Equality becomes difficult with inheritance.

You must also make your fields private by exposing them only as your own. If this will be used as a dictionary in a dictionary, I highly recommend that you make them read-only. Changing the contents of a key when used in a dictionary is likely to cause it to be “unreasonable” later.

+12
source

The default implementation of the GetHashCode method uses an object reference, not a value in the object. You must use the same instance of the object that was used to put the data into the dictionary for work.

The GetHashCode implementation that works just creates the code from the hash codes of its data members:

 public int GetHashCode() { return LowerLimit.GetHashCode() ^ UpperLimit.GetHashCode(); } 

(This is the same implementation that the Point structure uses.)

Any implementation of a method that always returns the same hash code for any given parameter values ​​works when used in a dictionary. Just returning the same hash code for all values ​​actually also works, but then the dictionary performance becomes poor (key search becomes O (n) operation instead of O (1) operation. To ensure better performance, the method should distribute the hash evenly codes within the range.

If your data is highly biased, the above implementation may not give the best performance. If you, for example, have many ranges where the lower and upper limits are the same, they will all receive a zero hash code. In this case, something like this might work better:

 public int GetHashCode() { return (LowerLimit.GetHashCode() * 251) ^ UpperLimit.GetHashCode(); } 

You should consider making the class immutable, i.e. make it read-only properties and only set them in the constructor. If you change the properties of an object during its use in the dictionary, its hash code will change and you will no longer be able to access the object.

+7
source

Source: https://habr.com/ru/post/1285887/


All Articles