Inject GetHashCode into a class that has a wildcard.

Suppose I want to be able to compare 2 ints lists and treat one specific value as a wild card.

eg. If -1 is a wild card, then

{1,2,3,4} == {1,2,-1,4} //returns true

And I am writing a class to wrap all this logic, so it implements IEquatable and has the corresponding logic in public override bool Equals()

But I always thought that you had to implement GetHashCode more or less if you redefined .Equals() . If this were not done by the compiler, but I got the impression that if you do not, you will do it wrong.

Also, I don’t see how I can implement .GetHashCode() without breaking its contract (objects with equal have different hashes) or just have return 1 implementation.

Thoughts?

+7
hashcode c # wildcard iequatable
source share
9 answers

This implementation of Equals no longer valid, as it is not transitive . You should probably leave Equals with the default implementation and write a new method like WildcardEquals (as suggested in other answers here).

In general, whenever you change Equals , you must implement GetHashCode if you want to be able to store objects in a hash table (for example, a Dictionary<TKey, TValue> ) and whether it works correctly. If you know for sure that objects will never end up in a hash table, then this is theoretically optional (but in this case it would be safer and clearer to redefine it to throw a " NotSupportedException " or always return 0 ).

The general contract is to always implement GetHashCode if you override Equals , as you cannot always be sure in advance that users will not put your objects in hashtables later.

+9
source share

In this case, instead of using operators, I created a new or expansion method WildcardEquals(other) .

I would not recommend hiding this complexity.

+6
source share

Logically, we violate the concept of equality. This is no longer transitive. Therefore, in the case of wildcards, A==B and B==C does not mean that A==C

Technically speaking, returning the same value from GetHashCode() not unforgivable.

+4
source share

The only possible idea that I see is to use at least length, for example:

 public override int GetHashCode() { return this.Length.GetHashCode() } 
+3
source share

Recommended, but not required. If you don't need this custom implementation of GetHashCode , just don't do it.

+2
source share

GetHashCode , as a rule, is important only if you are going to store the elements of your class in some collection, for example, in a set. If this is the case here, then I don’t think you can achieve consistent semantics, since @AlexD points to equality, which is no longer transitive.

For example (using string globes, not whole lists), if you add the strings "A", "B" and "*" to your set, your set will contain one or two elements, depending on which to add them.

If this is not what you want, I would recommend matching the wildcard in the new method (e.g. EquivalentTo() ) rather than overloading the equality.

+2
source share

If GetHashCode () always returns a constant, this is the only "legitimate" way to fulfill the equals / hashcode constraint.

This would potentially be ineffective if you put it in a hash map or similar, but it might be good (unequal hash codes imply disequilibrium, but equal hash codes imply nothing).

I think this is the only option. Haskodes essentially exist as keys for quickly finding things, and since your template must match each element, its search key must equal each element of the key, so they should all be the same.

As others have noted, this is not something that usually means equal, and breaks the assumption that many other things can be used for equals (for example, transitivity is EDIT: it turns out that this is actually a contract requirement, therefore non-go), so it is definitely at least it is worth considering comparing them manually or with a clearly separate comparison of equalities.

+2
source share

Since you have changed what equals means (adding to wildcards makes a big difference), you are already beyond the usual use of Equals and GetHashCode. This is just a recommendation, and in your case it seems that it is not suitable. So don’t worry about it.

However, make sure you are not using your class in places where GetHashCode can be used. This can cause you trouble and be difficult to debug if you are not looking at it.

+1
source share

It is usually assumed that Equals(Object) and IEquatable<T>.Equals(T) should implement equivalence relations such that if X is considered equal to Y, and Y is considered equal to Z, and none of the elements have been changed, X can be considered equal to Z; moreover, if X is equal to Y, and Y is not equal to Z, then X can be considered not equal to Z. Methods of comparison with Wild-card and fuzzy comparisons do not implement the equivalence relationship, and therefore Equals , as a rule, cannot be implemented with such semantics .

Many collections will sort the work with objects that implement Equals in such a way that they do not implement the equivalence relationship, provided that any two objects that can be compared with each other always return the same hash code. This often requires that many things be compared unevenly in order to return the same hash code, although depending on what types of wildcards are supported, it may be possible to separate the elements to some extent.

For example, if the only wildcard supported by a particular string is “an arbitrary string of one or more digits”, you could hash the string by converting all sequences of consecutive digits and / or character characters as a string to a single character “string of digits” . If # represents any digit, then the lines abc123, ab #, abc456 and ab # 93 # 22 # 7 will be hashed to the same value as ab #, but ab # b, abc123b, etc. May hash to another value. Depending on the distribution of strings, such differences may or may not provide better performance than returning a constant value.

Note that even if one implements GetHashCode in such a way that equal objects give equal hashes, some collections may still behave strangely if the equality method does not implement the equivalence relation. For example, if the foo collection contains elements with the keys "abc1" and "abc2", attempts to access foo["abc#"] may optionally return the first element or the second. Attempts to remove the "ab #" key may arbitrarily delete one or both elements or may fail after deleting one element (its expected post-condition will not be fulfilled, since abc# will be in the collection even after removal).

Instead of comparing with jinx Equals to compare hash code equality, an alternative approach is to have a dictionary that holds for every possible line of wildcards that matches at least one line of the main collection with a list of lines that it could possibly match. Thus, if there are many lines that will correspond to ab #, they may have different hash codes; if the user enters "ab #" as a search query, the system will search for "ab #" in the wild-card dictionary and get a list of all the lines matching this template, which can then be viewed individually in the main dictionary.

+1
source share

All Articles