The following prints equals:
struct A
{
int x;
public A(int _x) { x = _x; }
public int Y
{
get
{
Random r = new Random();
return r.Next(0, 1000);
}
}
}
static void Main(string[] args)
{
A a1 = new A(1),a2 = new A(1);
if (a1.Equals(a2))
{
Console.Write("Equals");
}
else
{
Console.Write("Different");
}
}
Is there anyway to get C# to return false in that case? Meaning, to take the properties under consideration when comparing value types?
Write equal then hit "tab" button twice:
// override object.Equals
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
// TODO: write your implementation of Equals() here
throw new NotImplementedException();
return base.Equals(obj);
}
This is an automatically generated snippet. Now you can try something like:
// override object.Equals
public override bool Equals(object obj)
{
// checks for A versus A
if (obj == null || GetType() != obj.GetType())
{
return false;
}
// TODO: write your implementation of Equals() here
throw new NotImplementedException();
int compareThis=(A)obj.x;
return ((A)base).x==compareThis; // maybe casting is not needed
}
The recommended approach is to use IEquatable<T> instead of using the default inherited Equals method. The IEquatable generic interface defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
using System;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
A a1 = new A(1), a2 = new A(1);
//here the CLR will do a lot of unboxing and check operations via reflection in order to make a comparaison between fields value.
//just take a look bellow at the decompiled default Equals method how it's done
if (a1.Equals(a2))
{
Console.Write("Equals");
}
else
{
Console.Write("Different");
}
}
}
public struct A : IEquatable<A>
{
int x;
public A(int _x) { x = _x; }
public int Y
{
get
{
Random r = new Random();
return r.Next(0, 1000);
}
}
//here no boxing or unboxing is needed even if is a value type and the CLR will call this method first
public bool Equals(A other)
{
return this.Y == other.Y;
}
public override bool Equals(object obj)
{
//this is why a bad approach to compare both objects you need to unbox the struct arguments wich hurting performance
return this.Y == ((A)obj).Y;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
//default implementation
//public override bool Equals(object obj)
//{
// return base.Equals(obj);
//}
}
}
CLR Implementation
The CLR what's going underneath
public override bool Equals(object obj)
{
if (obj == null)
return false;
RuntimeType runtimeType = (RuntimeType) this.GetType();
if ((RuntimeType) obj.GetType() != runtimeType)
return false;
object a = (object) this;
if (ValueType.CanCompareBits((object) this))
return ValueType.FastEqualsCheck(a, obj);
FieldInfo[] fields = runtimeType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
for (int index = 0; index < fields.Length; ++index)
{
object obj1 = ((RtFieldInfo) fields[index]).UnsafeGetValue(a);
object obj2 = ((RtFieldInfo) fields[index]).UnsafeGetValue(obj);
if (obj1 == null)
{
if (obj2 != null)
return false;
}
else if (!obj1.Equals(obj2))
return false;
}
return true;
}
This is very similar to this question.
All you need to do is to override the Equals method:
struct A
{
int x;
public A(int _x) { x = _x; }
public int Y
{
get
{
Random r = new Random();
return r.Next(0, 1000);
}
}
public override bool Equals(object obj)
{
//compare whatever you want...
}
}
}
Override equal method and return true or false based on property comparison.
Related
I have a class A, which holds a string property and overwrites Equals for equality testing.
public class A
{
public string Prop { get; }
public A(string val)
{
Prop = val;
}
public override bool Equals(object obj)
{
return obj is A arg && (Prop == arg.Prop);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
I also have a class B which has a List<A> as property:
public class B
{
public IReadOnlyList<A> Prop { get; }
public B(IReadOnlyList<A> val)
{
Prop = val;
}
public override bool Equals(object obj)
{
// ...
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
I wanna be able to compare to instances of B for equality and order.
How can I write the Equals method in B by not rewriting the same code I wrote in A?
Is there a way to reuse the A Equals?
Update: My first version assumed B is derived from A.
A.Equals:
If A is not sealed, obj is A ... can return a false positive if different types are compared. So the corrected version:
public override bool Equals(object obj)
{
return obj is A other
&& this.Prop == other.Prop
&& this.GetType() == other.GetType(); // not needed if A is sealed
}
A.GetHashCode:
base.GetHashCode will return different hash codes for different but equal instances, which is wrong. Derive the hashcode from self properties instead. If Prop acts like some ID, then simply return Prop.GetHashCode()
B.Equals:
public override bool Equals(object obj)
{
return obj is B other
&& this.Prop.SequenceEqual(other.Prop) // will re-use A.Equals
&& this.Prop.GetType() == other.Prop.GetType() // not needed if different IReadOnlyList types are ok
&& this.GetType() == other.GetType(); // not needed if B is sealed
}
B.GetHashCode:
You can aggregate the hash codes of A instances. Here I use a simple XOR but if the same items can often come in a different order you can come up with something more fancy.
return Prop.Aggregate(0, (h, i) => h ^ i.GetHashCode());
Implementing Equals for a list can be done by using the SequenceEquals method (from System.Linq namespace), which ensures that each item in one list equals the item at the same index in the other list.
One thing you might consider changing, however is your implementation of GetHashCode. This method should return the same number if two items are equal (though it's not guaranteed that two items with the same hash code are equal). Using base.GetHashCode() does not meet this requirement, since the base is object in this case; according to the documentation, "hash codes for reference types are computed by calling the Object.GetHashCode method of the base class, which computes a hash code based on an object's reference", so objects only return the same HashCode if they refer to the exact same object.
The HashCode should be based on the same properties used to determine equality, so in this case we want to use Prop.GetHashCode() for class A, and we want to aggregate the hashcode for all the items in Prop for class B.
Here's one way the classes could be refactored:
public class A : IEquatable<A>
{
public string Prop { get; }
public A(string val)
{
Prop = val;
}
public bool Equals(A other)
{
if (other == null) return false;
return Prop == other.Prop;
}
public override bool Equals(object obj)
{
return Equals(obj as A);
}
public override int GetHashCode()
{
return Prop.GetHashCode();
}
}
public class B : IEquatable<B>
{
public IReadOnlyList<A> Prop { get; }
public B(IReadOnlyList<A> val)
{
Prop = val;
}
public bool Equals(B other)
{
if (other == null) return false;
if (ReferenceEquals(this, other)) return true;
if (Prop == null) return other.Prop == null;
return other.Prop != null && Prop.SequenceEqual(other.Prop);
}
public override bool Equals(object obj)
{
return Equals(obj as B);
}
public override int GetHashCode()
{
return Prop?.Aggregate(17,
(current, item) => current * 17 + item?.GetHashCode() ?? 0)
?? 0;
}
}
Linq contains a useful method to compare collections: SequenceEqual
public override bool Equals(object obj)
{
if (!(obj is B other))
{
return false;
}
if (this.Prop == null || other.Prop == null)
{
return false;
}
return this.Prop.SequenceEqual(other.Prop);
}
Also, implement IEquatable<T> when you override Equals.
How about something like this:
public override bool Equals(object obj)
{
if(!(obj is B))
{
return false;
}
var b = obj as B;
if(b.Prop.Count != this.Prop.Count)
{
return false;
}
for(var i =0; i < Prop.Count; i++)
{
if (!Prop.ElementAt(i).Equals(b.Prop.ElementAt(i)))
{
return false;
}
}
return true;
}
Following (incorrect/dangerous) code
class EvilClass
{
protected int x;
public EvilClass(int x)
{
this.x = x;
}
public override bool Equals(Object obj)
{
if ((obj == null) || !this.GetType().Equals(obj.GetType()))
{
return false;
}
else
{
EvilClass p = (EvilClass)obj;
p.x = 42;
return (x == p.x);
}
}
public override int GetHashCode()
{
return (x << 2);
}
public override string ToString()
{
return String.Format("EvilClass({0})", x);
}
}
void Main()
{
var e1 = new EvilClass(1);
var e2 = new EvilClass(2);
var equals = e1.Equals(e2);
Console.WriteLine("{0}", e1.ToString());
Console.WriteLine("{0}", e2.ToString());
}
Output:
EvilClass(1)
EvilClass(42)
As you can see, call of e1.Equals(e2) modify e2. If we mark parameter as in compiler would not allow us to modify it.
Object.Equals() not suppose to change it's parameter - so why parameter is not in (input) parameter?
The most obvious reason is that in was introduced in C# 7.2, while object.Equals has been around since the very first version of .net.
The other reason is that it wouldn't actually change anything. in prevents from mutating the reference, not the actual object. If you try this:
public bool Equals2(in Object obj)
{
if ((obj == null) || !this.GetType().Equals(obj.GetType()))
{
return false;
}
else
{
EvilClass p = (EvilClass)obj;
p.x = 42;
return (x == p.x);
}
}
Then the output will still be:
EvilClass(1)
EvilClass(42)
I have a C# struct which I use as the key in a standard Dictionary collection. I've written overrides for both its GetHashCode and Equals, but I'm a little unhappy that Equals is given a boxed object instead of a reference to my struct type directly.
Is there anything I can do to optimize my use of Dictionary with my struct type to avoid the unnecessary boxing operation?
(This isn't premature optimization but entirely appropriate optimization, thank you very much.)
You could implement a generic comparer:
public class MyStructComparer : IEqualityComparer<MyStruct>
{
public bool Equals(MyStruct x, MyStruct y)
{
// ...
}
public int GetHashCode(MyStruct obj)
{
// ...
}
}
Then use that for the dictionary constructor:
var myStructDict = new Dictionary<MyStruct, string>(new MyStructComparer());
Another way is to implement IEquatable<MyStruct> in MyStruct, for example:
public struct MyStruct: IEquatable<MyStruct>
{
public int Id;
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
return obj is MyStruct && Equals((MyStruct)obj);
}
public bool Equals(MyStruct other)
{
return this.Id == other.Id;
}
public override int GetHashCode()
{
return this.Id;
}
}
Then the dictionary can be initialized with the default constructor:
var myStructDict = new Dictionary<MyStruct, string>();
You may also try for operator over loading.
check the code below.
struct MyStruct
{
public int id;
public static bool operator ==(MyStruct s1, MyStruct s2)
{
if (s1.id == s2.id)
return true;
return false;
}
public static bool operator !=(MyStruct s1, MyStruct s2)
{
if (s1.id == s2.id)
return false;
return true;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
return obj is MyStruct && Equals((MyStruct)obj);
}
public bool Equals(MyStruct other)
{
return this.id == other.id;
}
public override int GetHashCode()
{
return this.id;
}
}
I have a dictionary:
Dictionary<HashSet<myClass>, List<MyObj>> myDict = ...
And I have:
HashSet<myClass> myHashSet = ...
I want to check if the dictionary (myDict) contains myHashSet.
I tried to override two methods:
1) equal
2) GetHashCode
public class myClass
{
public string id;
public int number;
public override bool Equals(object obj)
{
myClass other = obj as myClass;
bool ret = false;
if (other != null)
{
ret = (this.number == other.number) && (this.id == other.id);
}
return ret;
}
public override int GetHashCode()
{
return this.number ^ this.id.GetHashCode();
}
};
Unfortunately, a key that is found in dictionary, returns false for the code:
myDict.ContainsKey(myHashSet)
Any help appreciated!
Just because you overrode myClass's Equals( and GetHashCode() does not mean that that you overrode HashSet<myClass>'s Equals( and GetHashCode(), that is what is being used when you do the dictionary lookup.
If you want it to work you need to pass a IEqualityComparer<HashSet<myClass>> in to the constructor of the dictionary so it will use that comparer when doing the dictionary lookup.
public class myClassSetComperer : IEqualityComparer<HashSet<myClass>>
{
public bool Equals(HashSet<myClass> x, HashSet<myClass> y)
{
if (ReferenceEquals(x, y)) return true;
if (ReferenceEquals(null, x)) return false;
if (ReferenceEquals(null, y)) return false;
return x.SetEquals(y);
}
public int GetHashCode(HashSet<myClass> obj)
{
unchecked
{
int x = 0;
foreach (var myClass in obj)
{
x = (x*397) ^ myClass?.GetHashCode() ?? 0;
}
return x;
}
}
}
//elsewhere
Dictionary<HashSet<myClass>, List<MyObj>> myDict = new Dictionary<HashSet<myClass>, List<MyObj>>(new myClassSetComperer());
VERY IMPORTANT NOTE: Dictionary keys (and hash sets) break horribly if you do anything that causes Equals( or GetHashCode() to change once put in as the lookup key. If you modify the HashSet<myClass> or one of the myClass objects after you put it in the dictionary you will break the dictionary and potentially the HashSet. See this very good blog post by Eric Lippert on "Guidelines and rules for GetHashCode"
overriding the GetHasCode and Equal is when comparing instances of myClass.
Here's a sample of using ContainsKey, which is checking by objects reference.
Dictionary<HashSet<string>, List<string>> hashSetDictionary = new Dictionary<HashSet<string>, List<string>>();
var myHashSet = new HashSet<string>();
hashSetDictionary.Add(myHashSet, null);
Console.WriteLine(hashSetDictionary.ContainsKey(myHashSet));
Here's an update to your code
public class myClass
{
public myClass(string text, int num)
{
this.Text = text;
this.Num = num;
}
public string Text { get; set; }
public int Num { get; set; }
}
public class MyObj { }
public class AlwaysTrueHashSet<T> : HashSet<T>
{
public override bool Equals(object obj)
{
return this.GetHashCode() == obj.GetHashCode();
}
public override int GetHashCode()
{
return "Counting hashcode".GetHashCode();
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<HashSet<myClass>, List<MyObj>> myDict = new Dictionary<HashSet<myClass>,
List<MyObj>>();
var myHashSet1 = new AlwaysTrueHashSet<myClass>();
myHashSet1.Add(new myClass("123", 5));
myDict.Add(myHashSet1, null);
var myHashSet2 = new AlwaysTrueHashSet<myClass>();
myHashSet2.Add(new myClass("123", 5));
/*
* when containsKey is invoked, it's checking if the reference of myHashSet2 is the same as myHashSet1.
* That's the default behavior.
*
* extend HashSet, and override the gethashcode and equal methods
*/
if (myDict.ContainsKey(myHashSet2))
{
Console.WriteLine("in");
int i = 3; // it doesn't get this line }
}
}
}
How can I define whether and how a comparison operator is applied to operands of my type?
You implement the IComparable interface with the CompareTo method.
To use all of the operators, try this:
public sealed class Foo : IEquatable<Foo>, IComparable<Foo>
{
public static int Compare(Foo first, Foo second)
{
if (Object.ReferenceEquals(first, null))
return (Object.ReferenceEquals(second, null) ? 0 : -1);
return first.CompareTo(second);
}
public static bool operator==(Foo first, Foo second)
{
return Object.Equals(first, second);
}
public static bool operator!=(Foo first, Foo second)
{
return !Object.Equals(first, second);
}
public static bool operator<(Foo first, Foo second)
{
return Foo.Compare(first, second) < 0;
}
public static bool operator >(Foo first, Foo second)
{
return Foo.Compare(first, second) > 0;
}
public static bool operator <=(Foo first, Foo second)
{
return Foo.Compare(first, second) <= 0;
}
public static bool operator >=(Foo first, Foo second)
{
return Foo.Compare(first, second) >= 0;
}
private string bar;
public string Bar
{
//getter and setter
}
public bool Equals(Foo other)
{
if (Object.ReferenceEquals(other, null))
return false;
if (Object.ReferenceEquals(other, this)) //Not mandatory
return true;
return String.Equals(this.foo, other.foo);
}
public int CompareTo(Foo other)
{
if (Object.ReferenceEquals(other, null))
return 1;
if (Object.ReferenceEquals(other, this)) //Not mandatory
return 0;
return String.Compare(this.bar, other.bar);
}
public override bool Equals(object obj)
{
return this.Equals(obj as Foo);
}
public override int GetHashCode()
{
return this.bar == null ? 0 : this.bar.GetHashCode();
}
}
A good tutorial on this: http://winsharp93.wordpress.com/2009/06/28/implementing-icomparablet-iequatablet-and-the-equality-members/
Since you know the interfaces IComparable, IEquatable needs to be implemented you can tell if two instances of yourClass are comparable by using this (example):
if (yourClass is IEquatable<T> && yourClass2 is IEquatable<T> && yourClass is IComparable<T> && yourClass2 is IComparable<T>) //T is the same type
{
yourClass <= yourClass2;
}
You can overload operators for your type, e.g.
public class MyComparable
{
public static bool operator <(MyComparable left, MyComparable right)
{
// other things...
}
Allows you to do this:
MyComparable c1 = // something
MyComparable c2 = // something
if (c1 < c2)
// something
(in such a case, it would probably make sense to implement IComparable<MyComparable> also.
A simple class that implements IComparable, IComparable<T>, IEquatable<T> and overrides object.Equals(object), object.GetHashCode() and the various "standard" operators ==, !=, >, <, >=, <=.
Note the use of object.ReferenceEquals(object, object) so as not to trigger StackOverflowException. This because we are overloading the == and != operators and basing them on MyClass.Equals(MyClass), so MyClass.Equals(MyClass) clearly can't use them. A common error is, in fact, inside the
bool Equals(MyClass other)
{
if (other == null)
{
}
}
Booooom! Can't do that. Because the if (other == null) will recursively call the other.Equals((MyClass)null). What you could do is: if (((object)other) == null), because in C# operators can't be virtual, so here we are using the == of the object class.
InnerEquals and InnerCompareTo are present so the null check mustn't be done twice if the Equals(object) or CompareTo(object) are called.
public class MyClass : IComparable<MyClass>, IComparable, IEquatable<MyClass>
{
public int MyInt1 { get; set; }
public int MyInt2 { get; set; }
public int CompareTo(MyClass other)
{
if (object.ReferenceEquals(other, null))
{
return 1;
}
return this.InnerCompareTo(other);
}
int IComparable.CompareTo(object obj)
{
// obj is object, so we can use its == operator
if (obj == null)
{
return 1;
}
MyClass other = obj as MyClass;
if (object.ReferenceEquals(other, null))
{
throw new ArgumentException("obj");
}
return this.InnerCompareTo(other);
}
private int InnerCompareTo(MyClass other)
{
// Here we know that other != null;
if (object.ReferenceEquals(this, other))
{
return 0;
}
int cmp = this.MyInt1.CompareTo(other.MyInt1);
if (cmp == 0)
{
cmp = this.MyInt2.CompareTo(other.MyInt2);
}
return cmp;
}
public override bool Equals(object obj)
{
// obj is object, so we can use its == operator
if (obj == null)
{
return false;
}
MyClass other = obj as MyClass;
if (object.ReferenceEquals(other, null))
{
return false;
}
return this.InnerEquals(other);
}
public bool Equals(MyClass other)
{
if (object.ReferenceEquals(other, null))
{
return false;
}
return this.InnerEquals(other);
}
private bool InnerEquals(MyClass other)
{
// Here we know that other != null;
if (object.ReferenceEquals(this, other))
{
return true;
}
return this.MyInt1 == other.MyInt1 && this.MyInt2 == other.MyInt2;
}
public override int GetHashCode()
{
unchecked
{
// From http://stackoverflow.com/a/263416/613130
int hash = 17;
hash = hash * 23 + this.MyInt1;
hash = hash * 23 + this.MyInt2;
return hash;
}
}
public static bool operator==(MyClass a, MyClass b)
{
if (object.ReferenceEquals(a, null))
{
return object.ReferenceEquals(b, null);
}
return a.Equals(b);
}
// The != is based on the ==
public static bool operator!=(MyClass a, MyClass b)
{
return !(a == b);
}
public static bool operator>(MyClass a, MyClass b)
{
if (object.ReferenceEquals(a, null))
{
return false;
}
return a.CompareTo(b) > 0;
}
// The <, >=, <= are all based on the >
public static bool operator <(MyClass a, MyClass b)
{
return b > a;
}
public static bool operator >=(MyClass a, MyClass b)
{
//return !(a < b);
//We short-circuit the <operator, because we know how it's done
return !(b > a);
}
public static bool operator <=(MyClass a, MyClass b)
{
return !(a > b);
}
}
And this one is the variant for struct types. A lot shorter, because nearly all the object.ReferenceEquals(object, object) are gone. Value types can't be null.
public struct MyStruct : IComparable<MyStruct>, IComparable, IEquatable<MyStruct>
{
public int MyInt1 { get; set; }
public int MyInt2 { get; set; }
public int CompareTo(MyStruct other)
{
return this.InnerCompareTo(other);
}
int IComparable.CompareTo(object obj)
{
if (obj == null)
{
return 1;
}
if (!(obj is MyStruct))
{
throw new ArgumentException("obj");
}
MyStruct other = (MyStruct)obj;
return this.InnerCompareTo(other);
}
private int InnerCompareTo(MyStruct other)
{
int cmp = this.MyInt1.CompareTo(other.MyInt1);
if (cmp == 0)
{
cmp = this.MyInt2.CompareTo(other.MyInt2);
}
return cmp;
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (!(obj is MyStruct))
{
throw new ArgumentException("obj");
}
MyStruct other = (MyStruct)obj;
return this.InnerEquals(other);
}
public bool Equals(MyStruct other)
{
return this.InnerEquals(other);
}
private bool InnerEquals(MyStruct other)
{
return this.MyInt1 == other.MyInt1 && this.MyInt2 == other.MyInt2;
}
public override int GetHashCode()
{
unchecked
{
// From http://stackoverflow.com/a/263416/613130
int hash = 17;
hash = hash * 23 + this.MyInt1;
hash = hash * 23 + this.MyInt2;
return hash;
}
}
// The != is based on the ==
public static bool operator ==(MyStruct a, MyStruct b)
{
return a.Equals(b);
}
public static bool operator !=(MyStruct a, MyStruct b)
{
return !(a == b);
}
public static bool operator >(MyStruct a, MyStruct b)
{
return a.CompareTo(b) > 0;
}
// The <, >=, <= are all based on the >
public static bool operator <(MyStruct a, MyStruct b)
{
return b > a;
}
public static bool operator >=(MyStruct a, MyStruct b)
{
//return !(a < b);
//We short-circuit the <operator, because we know how it's done
return !(b > a);
}
public static bool operator <=(MyStruct a, MyStruct b)
{
return !(a > b);
}
}