I have a class named Class1
I override its Equals function
Now I have an instance of Dictionary
And I added an instance of Class1 named OBJ1 to it.
I have another instance of Class1 named OBJ2.
the code returns true for OBJ1.Equals(OBJ2).
But I can't find OBJ2 in dictionary.
Here is pseudo code
Class1 OBJ1 = new Class1(x, y, z);
Class1 OBJ2 = new Class1(a, b, c);
Dictionary<Class1, int> dic1 = new Dictionary<Class1, int>();
dic1.Add(OBJ1, 3);
OBJ1.Equals(OBJ2) -------------> return true
Dictionary.ContainsKey(OBJ2) --------------> return false
why is this happening?
any help would be highly welcomed
2 possibilities:
GetHashCode has not been overridden correctly. You might want to take a look at Why is it important to override GetHashCode when Equals method is overriden in C#?
OBJ1 has been mutated after it has been added to the dictionary in a way that impacts its hashcode. In this case, the bucket it is placed in will no longer be correct - ContainsKey will end up hunting for it in a different bucket.
From Dictionary<TKey, TValue>:
As long as an object is used as a key
in the Dictionary, it
must not change in any way that
affects its hash value.
Chances are you haven't overridden GetHashCode in a manner consistent with Equals.
The contract of GetHashCode requires that if OBJ1.Equals(OBJ2) returns true, then OBJ1.GetHashCode() must return the same value as OBJ2.GetHashCode().
IIRC, you'll get a compiler error (or at least a warning) if you override Equals without overriding GetHashCode().
Another possibility is that you haven't actually overridden Equals, but overloaded it by adding a new signature, e.g.
public bool Equals(Class1 other)
In general, to provide a "natural" value equality comparison you should:
Override Equals(object)
Override GetHashCode
Strongly consider implementing IEquatable<T>
Consider overloading == and !=
You probably did not override GetHashcode in your class. When you override Equals you must override GetHashcode as well, else Dictionary won't work for you.
Make certain Class1 overrides GetHashCode(). The return from that method is the first thing checked when comparing equality. The default implementation is unique for each object.
Did you override GetHashCode as well ?
Can you display the implementation of the Equals method ?
Did you override the GetHashCode either?
You need to override GetHashCode as well, but also don't forget that you may need to pass in a custom Comparer to the Dictionary constructor as well as pointed out in this SO question
Related
I have a reference type that implements the IEquatable Interface. I have a Hashset that contains a single object. I then create an object that, by IEquatable's standards are example the same. But, when I run
var equivalentEntry = _riskControlATMEntries[grouping.Key].FirstOrDefault(e => e == atmEntry);
on the object I get null.
On the otherhand when I do
var equivalentEntry = _riskControlATMEntries[grouping.Key].FirstOrDefault(e => e.Equals(atmEntry));
I get the object that is considered equal based on the IEquatable interface's implementation.
So why does a HashSet rely on public bool Equals(ReferenceType other) but FirstOrDefault does not? What equality is the == operator in FirstOrDefault(e => e == other) looking for?
FirstOrDefault doesn't compare items for equality at all. You provided a filtering delegate that uses the == operator to compare the two objects in one case and used the Equals method in the other.
The == operator does whatever the class defines it to do by that type, or if not defined, by the closest base type that does (with object being the base type that is always there, and will always have a definition if nothing better was defined; it will compare objects based on their reference). Good design says that you should make sure the == operator for a class is defined to behave exactly the same as the Equals method, but nothing in the language forces you to do this, and apparently this class doesn't ensure they're the same, and it's unsurprisingly causing you problems.
I have been reading articles and understand interfaces to an extent however, if i wanted to right my own custom Equals method, it seems I can do this without implementing the IEquatable Interface. An example.
using System;
using System.Collections;
using System.ComponentModel;
namespace ProviderJSONConverter.Data.Components
{
public class Address : IEquatable<Address>
{
public string address { get; set; }
[DefaultValue("")]
public string address_2 { get; set; }
public string city { get; set; }
public string state { get; set; }
public string zip { get; set; }
public bool Equals(Address other)
{
if (Object.ReferenceEquals(other, null)) return false;
if (Object.ReferenceEquals(this, other)) return true;
return (this.address.Equals(other.address)
&& this.address_2.Equals(other.address_2)
&& this.city.Equals(other.city)
&& this.state.Equals(other.state)
&& this.zip.Equals(other.zip));
}
}
}
Now if i dont implement the interface and leave : IEquatable<Address> out of the code, it seems the application operates exactly the same. Therefore, I am unclear as to why implement the interface? I can write my own custom Equals method without it and the breakpoint will hit the method still and give back the same results.
Can anyone help explain this to me more? I am hung up on why include "IEquatable<Address>" before calling the Equals method.
Now if i dont implement the interface and leave : IEquatable out of the code, it seems the application operates exactly the same.
Well, that depends on what "the application" does. For example:
List<Address> addresses = new List<Address>
{
new Address { ... }
};
int index = addresses.IndexOf(new Address { ... });
... that won't work (i.e. index will be -1) if you have neither overridden Equals(object) nor implemented IEquatable<T>. List<T>.IndexOf won't call your Equals overload.
Code that knows about your specific class will pick up the Equals overload - but any code (e.g. generic collections, all of LINQ to Objects etc) which just works with arbitrary objects won't pick it up.
The .NET framework has confusingly many possibilities for equality checking:
The virtual Object.Equals(object)
The overloadable equality operators (==, !=, <=, >=)
IEquatable<T>.Equals(T)
IComparable.CompareTo(object)
IComparable<T>.CompareTo(T)
IEqualityComparer.Equals(object, object)
IEqualityComparer<T>.Equals(T, T)
IComparer.Compare(object, object)
IComparer<T>.Compare(T, T)
And I did not mention the ReferenceEquals, the static Object.Equals(object, object) and the special cases (eg. string and floating-point comparison), just the cases where we can implement something.
Additionally, the default behavior of the first two points are different for structs and classes. So it is not a wonder that a user can be confused about what and how to implement.
As a thumb of rule, you can follow the following pattern:
Classes
By default, both the Equals(object) method and equality operators (==, !=) check reference equality.
If reference equality is not right for you, override the Equals method (and also GetHashCode; otherwise, your class will not be able to be used in hashed collections)
You can keep the original reference equality functionality for the == and != operators, it is common for classes. But if you overload them, it must be consistent with Equals.
If your instances can be compared to each other in less or greater meaning, implement the IComparable interface. When Equals reports equality, CompareTo must return 0 (again, consistency).
Basically that's it. Implementing the generic IEquatable<T> and Comparable<T> interfaces for classes is not a must: as there is no boxing, the performance gain would be minimal in the generic collections. But remember, if you implement them, keep the consistency.
Structs
By default, the Equals(object) performs a value comparison for structs (checks the field values). Though normally this is the expected behavior in case of a value type, the base implementation does this by using reflection, which has a terrible performance. So do always override the Equals(object) in a public struct, even if you implement the same functionality as it originally had.
When the Equals(object) method is used for structs, a boxing happens, which have a performance cost (not as bad as the reflection in ValueType.Equals, but it matters). That's why IEquatable<T> interface exists. You should implement it on structs if you want to use them in generic collections. Have I already mentioned to keep consistency?
By default, the == and != operators cannot be used for structs so you must overload them if you want to use them. Simply call the strongly-typed IEquatable<T>.Equals(T) implementation.
Similarly to classes, if less-or-greater is meaningful for your type, implement the IComparable interface. In case of structs, you should implement the IComparable<T> as well to make things performant (eg. Array.Sort, List<T>.BinarySearch, using the type as a key in a SortedList<TKey, TValue>, etc.). If you overloaded the ==, != operators, you should do it for <, >, <=, >=, too.
A little addendum:
If you must use a type that has an improper comparison logic for your needs, you can use the interfaces from 6. to 9. in the list. This is where you can forget consistency (at least considering the self Equals of the type) and you can implement a custom comparison that can be used in hash-based and sorted collections.
If you had overridden the Equals(object obj) method, then it would only be a matter of performances, as noted here: What's the difference between IEquatable and just overriding Object.Equals()?
But as long as you didn't override Equals(object obj) but provided your own strongly typed Equals(Adddress obj) method, without implementing IEquatable<T> you do not indicate to all classes that rely on the implementation of this interface to operate comparisons, that you have your own Equals method that should be used.
So, as John Skeet noted, the EqualityComparer<Address>.Default property used by List<Address>.IndexOf to compare addresses wouldn't be able to know it should use your Equals method.
IEquatable interface just adds Equals method with whatever type we supply in the generic param. Then the funciton overloading takes care of rest.
if we add IEquatable to Employee structure, that object can be compared with Employee object without any type casting. Though the same we can achieved with default Equals method which accepts Object as param,
So converting from Object to struct involves Boxing. Hence having IEquatable <Employee> will improve performance.
for example assume we want to compare Employee structure with another employee
if(e1.Equals(e2))
{
//do some
}
For above example it will use Equals with Employee as param. So no boxing nor unboxing is required
struct Employee : IEquatable<Employee>
{
public int Id { get; set; }
public bool Equals(Employee other)
{
//no boxing not unboxing, direct compare
return this.Id == other.Id;
}
public override bool Equals(object obj)
{
if(obj is Employee)
{ //un boxing
return ((Employee)obj).Id==this.Id;
}
return base.Equals(obj);
}
}
Some more examples:
Int structure implements IEquatable <int>
Bool structure implements IEquatable <bool>
Float structure implements IEquatable <float>
So if you call someInt.Equals(1) it doesn't fires Equals(object) method. it fires Equals(int) method.
Given an instance of an object in C#, how can I determine if that object has value semantics? In other words, I want to guarantee that an object used in my API is suitable to be used as a dictionary key. I was thinking about something like this:
var type = instance.GetType();
var d1 = FormatterServices.GetUninitializedObject(type);
var d2 = FormatterServices.GetUninitializedObject(type);
Assert.AreEqual(d1.GetHashCode(), d2.GetHashCode());
What do you think of that approach?
You can test for implementation of Equals() and GetHashCode() with this:
s.GetType().GetMethod("GetHashCode").DeclaringType == s.GetType()
or rather per #hvd's suggestion:
s.GetType().GetMethod("GetHashCode").DeclaringType != typeof(object)
Some some object s, if GetHashCode() is not implemented by it's type, this will be false, otherwise true.
One thing to be careful on is that this will not protect against a poor implementation of Equals() or GetHashCode() - this would evaluate to true even if the implementation was public override int GetHashCode() { }.
Given the drawbacks, I would tend towards documenting your types ("this type should / should not be used for a dictionary key..."), because this isn't something you could ultimately depend upon. If the implementation of Equals() or GetHashCode() was flawed instead of missing, it would pass this test but still have a run-time error.
FormatterServices.GetUninitializedObject can put the object in an invalid state; It breaks the guaranteed assignment of readonly fields etc. Any code which assumes that fields will not be null will break. I wouldn't use that.
You can check whether GetHashCode and Equals is overridden via reflection, but that's not enough. You could override the method call base class method. That doesn't count as value semantics.
Btw value semantics doesn't mean equal hashcodes. It could be a collision too; Value semantics means that two objects with equals properties should return same hashcode as well as equals method should evaluate to true.
I suggest you to create an instance, assign some properties, clone it; Now both hashcodes should be equal and calling object.Equals(original, clone) should evaluate to true.
You can see if an object defines its own Equals and GetHashCode using the DeclaringType property on the corresponding MethodInfo:
bool definesEquality = type.GetMethod("Equals", new[] { typeof(object) }).DelcaringType == type && type.GetMethod("GetHashCode", Type.EmptyTypes).DeclaringType == type;
Probably I miss something using a HashSet and HashCode, but I don´t know why this doesn't work as I thought. I have an object with the HashCode is overridden. I added the object to a HashSet and later I change a property (which is used to calculate the HashCode) then I can´t remove the object.
public class Test
{
public string Code { get; set; }
public override int GetHashCode()
{
return (Code==null)?0: Code.GetHashCode();
}
}
public void TestFunction()
{
var test = new Test();
System.Collections.Generic.HashSet<Test> hashSet = new System.Collections.Generic.HashSet<Test>();
hashSet.Add(test);
test.Code = "Change";
hashSet.Remove(test); //this doesn´t remove from the hashset
}
Firstly, you're overriding GetHashCode but not overriding Equals. Don't do that. They should always be overridden at the same time, in a consistent manner.
Next, you're right that changing an objects hash code will affect finding it in any hash-based data structures. After all, the first part of checking for the presence of a key in a hash-based structure is to find candidate equal values by quickly finding all existing entries with the same hash code. There's no way that the data structure can "know" that the hash code has been changed and update its own representation.
The documentation makes this clear:
You can override GetHashCode for immutable reference types. In general, for mutable reference types, you should override GetHashCode only if:
You can compute the hash code from fields that are not mutable; or
You can ensure that the hash code of a mutable object does not change while the object is contained in a collection that relies on its hash code.
public void TestFunction()
{
var test = new Test();
System.Collections.Generic.HashSet<Test> hashSet = new System.Collections.Generic.HashSet<Test>();
test.Code = "Change";
hashSet.Add(test);
hashSet.Remove(test); //this doesn´t remove from the hashset
}
first set the value into object of Test, then add it to HashSet.
HashCode is used to find object in the HashSet/ Dictionary. If hash code changed object no longer can be found in the HashSet because when looked up by new HashSet the bucket for items with that new hash code will not (most likely) contain the object (which is in bucket marked with old hash code).
Note that after initial search by hash code Equals will be used to perform final match, but it does not apply to your particular case as you have the same object and use default Equals that compares references.
Detailed explanation/guidelines - Guidelines and rules for GetHashCode by Eric Lippert.
I'm trying to write a Generic IEqualityComparer for an HashSet, such that two set are equals if and only if their elements match.
So, Equals will look like:
public bool Equals(HashSet<T> A, HashSet<T> B)
{
return (A.All(x => B.Contains(x)) && B.All(x => A.Contains(x)));
}
I am having much more trouble finding a good GetHashCode method. I am aware that
public int GetHashCode(HashSet<int> obj)
{
return 1;
}
is always an option, but I'd like to have something better than that. Has anybody an idea on how i could do that? Is using ToString on each element, order and join them, and get the hashcode for the resulting string a bad idea?
The IEqualityComparer<T> Interface abstract the set of operations required here:
Equals
GetHashode
You can get the default comparer like all .NET classes do: using the EqualityComparer<T>.Default Property
However, it is my understanding that HashSet<> has the policy to use the Comparer associated with the object that you invoke an operation on, even if it takes another HashSet as an argument.