I have a generic C# class comparer routine which reads values from objects and then compares their properties one by one using reflection.
var value1 = property.GetValue(object1, null);
var value2 = property.GetValue(object2, null);
if (!value1.Equals(value2))
{ ......
Thing is I'm getting differences in some of my float/double values that are insignificant and I want to ignore. What's the best way of implementing a specific test for floats/doubles (and potentially ints) that compares values based on a provided number of significant digits?
Take a look at the EqualityComparer<T> class.
Instead of comparing objects in the way you describe, you should rely on the Equals method of the type in question, imho.
That is, the author of the class should define when 2 instances of that class are equal, by overriding the Equals method (and perhaps even implementing the IEquality interface).
Related
I'm trying to exclude entities to be added to database if they already exist there. So I decided newBillInstances.Except(dbContext.BillInstances) would be best approach for that. However it doesn't work at all (no entities are excluded) though for List<string> it works perfectly.
I read this discussion and actual decription of .Except() in MSDN. It states the class to be used in .Except() should implement IEqualityComparer<T> to use default comparer.
Actually the MSDN article doesn't fully describe process of comparison of two instances. I still don't get why both Equals() and GetHashObject() have to be overridden.
I have implemented IEqualityComparer<BillInstance> interface and put break points in boths methods, but while calling .Except(IEnumerable) it's not used. Only when I changed to .Except(IEnumerable, new BillInstanceComparer()) I've cough break in GetHashCode() but no breaks where in Equals().
Then I have implemented IEqualityComparer<BillInstance> right in BillInstance class and expected it would be used while using .Except(IEnumerable) but breaks weren't hit in both methods.
So I've got two questions:
What should be done to use .Except(IEnumerable)?
Why Equals() isn't used at all? Is it used only in case hash codes of two instances are same?
Because the Equals() is used only if two objects have the same GetHashCode(). If there are no objects that have the same GetHashCode() then there is no chance of using the Equals().
Internally the Except() uses a Set<> (you can see it here), that is an internal class that you should consider to be equivalent to HashSet<>. This class uses the hash of the object to "index" them, then uses the Equals() to check if two objects that have the same hash are the same or different-but-with-the-same-hash.
Link to other relevant answer: https://stackoverflow.com/a/371348/613130
Somewhere in the code a set or a map/dictionary is hidden.
These guys typically contains a number of buckets which grows with the number of elements stored in the set. An element is partitioned into buckets based on the hash code and the actual identity comparison within the bucket is done using equals.
So the hash code is used to find the correct bucket (why GetHashCode is needed) whereupon equals is used to compare it to other elements in the buckets.
That's why you need to implement both.
Ok, from the IEnumerable source (thanks to m0sa) I've understood internals of calling Except(IEnumerable):
enumerable1.Except(enumerable2) calls ExceptIterator(enumerable1, enumerable2, null) where null is supposed to be an instance of IEquitableComparer.
ExceptIterator() creates an instance of internal class Set passing null as comparer.
Since comparer is null the property EqualityComparer<TElement>.Default is used.
Default property creates a comparer for TElement unless it's already created by calling CreateComparer(). Specifically 2 points were interesting for me:
If TElement implements IEquatable interface, then as far as I understood some generic comparer for IEquatable is created. I believe it would use then IEquatable.GetHashCode() and IEquatable.Equals().
For general cases (not type of byte, not implementing IEquatable, not Nullable, not enum) ObjectEqualityComparer instance is returned. ObjectEqualityComparer.GetHashCode() and ObjectEqualityComparer.Equals() generally call corresponding methods of the TElement.
So this gave me understanding for my case (each instance of BillInstance is generally immutable) it should be sufficient to override Object.GetHashCode() and Object.Equals().
Okay, I'm reading up on all the advice on how to override object.Equals and == for value and reference types. In short, always override equality for structs and don't override equality for Reference types unless you have some unusual circumstance like class that wraps a single string. (But don't make a struct unless it is small, even if semantically or DDD terms it is a value type)
But most of my types that hold data are DTOS-- classes with lots of properties. They have more properties that is suitable for a struct (more than 16 bytes) and will be consumed by developers who will expect == and object.Equals to behave as usual. All three scenarios come up-- needing to check for equality by reference, value (especially in unit testing) and by key (especially when working with data that came from or is going to a relational database.)
Is there a .NET framework way to implement equality-by-value or equality-by-key without stomping the default behavior of object.Equals? Or must I create my own ad hoc interface, like ISameByValue<T>, ISameByKey<T>?
Create IEqualityComparer types. This allows you to create any number of different types capable of comparing your object by any number of different definitions of equality, all without changing any behavior on the type itself.
I had a problem where I had implemented property based comparisons in the overridden Equals method (to implement HasChanges type functionality), but it caused all sorts of problems when I updated property values of items in a collection.
My solution (found by helpful users of this website) was to move the property based comparisons into a new, custom method and to return the default object.Equals value instead. However, this meant that there was no longer any based comparisons when calling the Equals method.
The solution was then to provide custom implementations of the IEqualityComparer<T> Interface and to pass the instances through to any methods that require object comparisons, like the IEnumerable Intersect or Except methods for example:
if (digitalServiceProvider.PriceTiers[index].Territories.Count > 0 &&
digitalServiceProvider.PriceTiers[index].Territories.Intersect(
release.TerritorialRights, new CountryEqualityComparer()).Count() == 0) { ... }
It always seems to just "work" without ever having to do anything.
The only thing I can think of is that each class has a hidden sort of static identifier that Object.GetHashCode uses. (also, does anyone know how Object.GetHashCode is implemented? I couldn't find it in the .NET Reflector)
I have never overridden GetHashCode but I was reading around and people say you only need to when overriding Equals and providing custom equality checking to your application so I guess I'm fine?
I'd still like to know how the magic works, though =P
It always seems to just "work" without ever having to do anything.
You didn't tell us if you're using value types or reference types for your keys.
If you're using value types, the default implementation of Equals and GetHashCode are okay (Equals checks if the fields are equals, and GetHashCode is based on the fields (not necessarily all of them!)). If you're using reference types, the default implementation of Equals and GetHashCode use reference equality, which may or may not be okay; it depends on what you're doing.
The only thing I can think of is that each class has a hidden sort of static identifier that Object.GetHashCode uses.
No. The default is a hash code based on the fields for a value type, and the reference for a reference type.
(also, does anyone know how Object.GetHashCode is implemented? I couldn't find it in the .NET Reflector)
It's an implementation detail that you should never ever need to know, and never ever rely on it. It could change on you at any moment.
I have never overridden GetHashCode but I was reading around and people say you only need to when overriding Equals and providing custom equality checking to your application so I guess I'm fine?
Well, is default equality okay for you? If not, override Equals and GetHashCode or implmenet IEqualityComparer<T> for your T.
I'd still like to know how the magic works, though =P
Every object has Equals and GetHashCode. The default implementations are as follows:
For value types, Equals is value equality.
For reference types, Equals is reference equality.
For value types, GetHashCode is based on the fields (again, not necessarily all of them!).
For reference types, GetHashCode is based on the reference.
If you use a overload of Dictionary constructor that doesn't take a IEqualityComparer<T> for your T, it will use EqualityComparer<T>.Default. This IEqualityComparer<T> just uses Equals and GetHashCode. So, if you haven't overridden them, you get the implementations as defined above. If you override Equals and GetHashCode then this is what EqualityComparer<T>.Default will use.
Otherwise, pass a custom implementation of IEqualityComparer<T> to the constructor for Dictionary.
Are you using your custom classes as keys or values? If you are using them only for values, then their GetHashCode doesn't matter.
If you are using them as keys, then the quality of the hash affects performance. The Dictionary stores a list of elements for each hash code, since the hash codes don't need to be unique. In the worst case scenario, if all of your keys end up having the same hash code, then the lookup time for the dictionary will like a list, O(n), instead of like a hash table, O(1).
The documentation for Object.GetHashCode is quite clear:
The default implementation of the GetHashCode method does not guarantee unique return values for different objects... Consequently, the default implementation of this method must not be used as a unique object identifier for hashing purposes.
Object's implementations of Equals() and GetHashCode() (which you're inheriting) compare by reference.
Object.GetHashCode is implemented in native code; you can see it in the SSCLI (Rotor).
Two different instances of a class will (usually) have different hashcodes, even if their properties are equal.
You only need to override them if you want to compare by value – if you want to different instances with the same properties to compare equal.
It really depends on your definition of Equality.
class Person
{
public string Name {get; set;}
}
void Test()
{
var joe1 = new Person {Name="Joe"};
var joe2 = new Person {Name="Joe"};
Assert.AreNotEqual(joe1, joe2);
}
If you have a different definition for equality, you should override Equals & GetHashCode to get the appropriate behavior.
Hash codes are for optimizing lookup performance in hash tables (dictionaries). While hash codes have a goal of colliding as little as possible between instances of objects they are not guaranteed to be unique. The goal should be equal distribution among the int range given a set of typical types of those objects.
The way hash tables work is each object implements a function to compute a hash code hopefully as distributed as possible amongst the int range. Two different objects can produce the same hash code but an instance of an object given it's data should always product the same hash code. Therefore, they are not unique and should not be used for equality. The hash table allocates an array of size n (much smaller than the int range) and when an object is added to the hash table, it calls GetHashCode and then it's mod'd (%) against the size of the array allocated. For collisions in the table, typically a list of objects is chained. Since computing hash codes should be very fast, a lookup is fast - jump to the array offset and walk the chain. The larger the array (more memory), the less collisions and the faster the lookup.
Objects GetHashCode cannot possibly produce a good hash code because by definition it knows nothing about the concrete object that's inheriting from it. That's why if you have custom objects that need to be placed in dictionaries and you want to optimize the lookups (control creating an even distribution with minimal collisions), you should override GetHashCode.
If you need to compare two items, then override equals. If you need the object to be sortable (which is needed for sorted lists) then override IComparable.
Hope that helps explain the difference.
I created to following code to verify the uniqueness of a series of "tuples":
struct MyTuple
{
public MyTuple(string a, string b, string c)
{
ValA = a; ValB = b; ValC = c;
}
private string ValA;
private string ValB;
private string ValC;
}
...
HashSet<MyTuple> tupleList = new HashSet<MyTuple>();
If I'm correct, I will not end up with two tuples with the same values in my HashSet thanks to the fact that I'm using a struct. I could not have the same behavior with a class without implementing IEquatable or something like that (I didn't dig too much how to do that).
I want to know if there is some gotcha about what I do. Performance wise, I wouldn't expect the use of a struct to be a problem considering that the string inside are reference types.
Edit:
I want my HashSet to never contains two tuples having string with the same values. In other words, I want the string to behave like values types.
The gotcha is that it will not work. If two strings are "a", they can still be different references. That case would break your implementation.
Implement Equals() and GetHashCode() properly (e.g. using the ones from the supplied strings, and take care with NULL references in your struct), and possibly IEquatable<MyTuple> to make it even nicer.
Edit: The default implementation is explicitly not suitable to be used in hash tables and sets. This is clearly stated in the ValueType.GetHashCode() implementation (added emphasis):
The GetHashCode method applies to
types derived from ValueType. One or
more fields of the derived type is
used to calculate the return value. If
you call the derived type's
GetHashCode method, the return value
is not likely to be suitable for use
as a key in a hash table.
Additionally, if the value of one or
more of those fields changes, the
return value might become unsuitable
for use as a key in a hash table. In
either case, consider writing your own
implementation of the GetHashCode
method that more closely represents
the concept of a hash code for the
type.
You should always implement Equals() and GetHashCode() as "pair", and this is even more obvious since the ValueType.Equals() is terribly inefficient and unreliable (using reflection, unknown method of equality comparison). Also, there is the performance problem when not overriding those two (structs will get boxed when calling the default implementations).
Your approach should work, but you should make the string values read-only, as Lucero said.
You could also take a look at the new .NET 4.0 Tuple types. Although they are implemented as classes (because of supporting up to quite many parameters), they implement the new interface IStructuralEquatable which is intended exactly for your purpose.
It depends on what you mean by "same values". If you want the strings themselves to be unequal to one another—rather than just the references—then you're going to have to write your own Equals(MyTuple) method.
I ran into this today when unit testing a generic dictionary.
System.Collections.Generic.Dictionary<int, string> actual, expected;
actual = new System.Collections.Generic.Dictionary<int, string> { { 1, "foo" }, { 2, "bar" } };
expected = new System.Collections.Generic.Dictionary<int, string> { { 1, "foo" }, { 2, "bar" } };
Assert.AreEqual(expected, actual); //returns false
fails except when actual == expected (object references are the same). Obviously, actual.Equals(expected) returns false as well.
Fine, but if the implementation of System.Collections.Generic.Dictionary<int, string>.Equals only does reference equality, what's the point of IEquatable? In other words, why is there no baked-in way to do value equality for generic collections?
Edit Thanks for the responses so far. Obviously my example is using value types, but I think my complaint holds for all objects. Why can't a generic collection equality just be a union of equalities of its types? Unexpected behavior doesn't really cut it since there are separate provisions for finding reference equality. I suppose this would introduce the constraint of collections only holding object that implement IEquatable, as Konrad Rudolph points out. However, in an object like Dictionary, this doesn't seem too much to ask.
In other words, why is there no baked-in way to do value equality for generic collections?
Probably because it's hard to formulate in generic terms, since this would only be possible if the value type (and key type) of the dictionary also implemented IEquatable. However, requiring this would be too strong, making Dictionary unusable with a lot of types that don't implement this interface.
This is an inherent problem with constrained generics. Haskell provides a solution for this problem but this requires a much more powerful and complicated generics mechanism.
Notice that something similar is true for IComparable in comparison with containers, yet there is support for this, using Comparer<T>.Default if necessary.
Dictionary<T,T>.Equals is inherited from Object.Equals and thus does a simple comparison of the object references.
Why do the generic collections not do value equality semantic? Because that may not be what you want. Sometimes you want to check if they're the same instance. What would the alternative do? Call Equals on each of the keys and values? What if these inherit Equals from Object? It wouldn't be a full deep comparison.
So it's up to you to provide some other semantic if and when necessary.
Dictionary<TKey, TValue> does not implement IEquatable, as such there is no formal way to determine/know what comparing one such dictionary to another with the same contents would actually produce.
In fact, Dictionary<TKey, TValue> does not implement any of the comparison interfaces at all.
In my opinion, to have two objects compare themselves is a rather special thing, so it would've made much more sense to put that into an interface than just to put a default typically-unwanted implementation in the base Object class. It should've been a more advertised feature of a class than something every object can do, albeit not quite the way you expect it to.
But there you have it. It's there, and you need to know when it's going to be used.
Like in this case.