Overriding Equals and GetHashCode doesn't necessarily override equality overloading operator - c#

I have the following code:
public enum ClassType
{
I,
II,
}
public enum LocationType
{
A,
B
}
public class Person
{
public LocationType LocType
{ get; set; }
public ClassType ClaType
{ get; set; }
public override bool Equals(object obj)
{
Person obPer = obj as Person;
if (obPer == null)
return false;
if (LocType != obPer.LocType)
return false;
if (ClaType != obPer.ClaType)
return false;
return true;
}
public override int GetHashCode()
{
return LocType.GetHashCode()^ClaType.GetHashCode();
}
}
static void Main(string[] args)
{
var p1 = new Person()
{
ClaType = ClassType.I,
LocType = LocationType.A
};
var p2 = new Person()
{
ClaType = ClassType.I,
LocType = LocationType.A
};
bool isEqual1 = p1.Equals(p2); //true
bool getHashCodeNum = p1.GetHashCode() == p2.GetHashCode(); //true
bool isEqual2 = p1 == p2; //false
}
I find that isEqual1=true, getHashCodeNum=true, but isEqual2=false.
I would expect that since I already override Equals and GetHashCode, then the operator == should automatically follow the behavior of Equals, but this is not so. Any reason?

An == is an operator. You can overload the == operator over two Persons as follows:
public class Person {
//..
public static bool operator == (Person a, Person b)
{
if (Object.ReferenceEquals(a,null) && Object.ReferenceEquals(b,null))
return true;
if (Object.ReferenceEquals(a,null) || Object.ReferenceEquals(a,null))
return false;
return a.LocType == b.LocType && a.ClaType != b.ClaType;
}
public static bool operator != (Person a, Person b)
{
return ! (a == b);
}
}
== and != are pairs: you need to implement != if you implement == and vice versa, otherwise you get the error:
error CS0216: The operator Person.operator ==(Person, Person) requires a matching operator != to also be defined
Now when you compare two Persons it should work. Mind however that you do not override equality operators, you overload them. So the compiler picks the == implementation (this is not done at runtime through a dynamic binding). As a result:
bool isEqual2 = p1 == p2; //true
bool isEqual3 = (object) p1 == p2; //false
bool isEqual4 = p1 == (object) p2; //false
bool isEqual5 = (object) p1 == (object) p2; //false
By default the == over two objects is reference equality so only if the two arguments are Persons here, we check whether the two persons are equivalent.
It is therefore probably better to use Equals(..) if you want to check equality with a dynamic binding.

Related

Equals operator on subclass as well as abstract class

Let's say we have the following simple classes:
abstract class Abc { }
class Bcd : Abc { public int val; }
By default, the == operator on Bcd instances will return false in this example:
var result_1 = new Bcd() { val = 10 } == new Bcd() { val = 10 };
So, following the guidance here the == operator can be added to Bcd:
class Bcd : Abc
{
public int val;
public bool Equals(Bcd obj)
{
if (Object.ReferenceEquals(obj, null)) return false;
if (Object.ReferenceEquals(obj, this)) return true;
if (obj.GetType() != GetType()) return false;
return obj.val == val;
}
public override bool Equals(object obj) => Equals(obj as Bcd);
public override int GetHashCode() => val.GetHashCode();
public static bool operator ==(Bcd a, Bcd b)
{
if (Object.ReferenceEquals(a, null))
{
if (Object.ReferenceEquals(b, null)) return true;
return false;
}
return a.Equals(b);
}
public static bool operator !=(Bcd a, Bcd b) => !(a == b);
}
And now, the expression evaluates to true:
var result_1 = new Bcd() { val = 10 } == new Bcd() { val = 10 };
However, I may want to store instances of Bcd (and perhaps other instances of other subclasses of Abc) in variables typed as Abc:
Abc a = new Bcd() { val = 10 };
Abc b = new Bcd() { val = 10 };
Now, this of course will return false:
var result_2 = a == b;
One way to get the desired behaviour is to add equality methods to Abc as well (even though it is an abstract class):
abstract class Abc
{
public bool Equals(Abc obj)
{
if (obj is Bcd && this is Bcd) return (obj as Bcd) == (this as Bcd);
return false;
}
public static bool operator ==(Abc a, Abc b)
{
if (Object.ReferenceEquals(a, null))
{
if (Object.ReferenceEquals(b, null)) return true;
return false;
}
return a.Equals(b);
}
public static bool operator !=(Abc a, Abc b) => !(a == b);
}
Now the expression returns true:
Abc a = new Bcd() { val = 10 };
Abc b = new Bcd() { val = 10 };
var result_2 = a == b;
My question is, is adding the equality operator (and Equals method, != operator, etc.) to the abstract parent class Abc in the above way the recommended approach? It feels a little boilerplate-ish. Moreover, if Abc is subclassed again in the future, the Equals operator in Abc needs to be updated; this also feels a little odd.
Is there any recommended guide for this pattern?

Why parameter of Object.Equals is not 'in' (input)?

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)

Compare 2 class objects and ignore 1 (or more) property?

So I created a class like this:
public class ClassName
{
public int ID;
public String n_1 {get; set; }
public String n_2 {get; set; }
// ....
public String n_x {get; set; }
}
Later in my code I compare 2 ClassName objects:
ClassName Item_1 /*...*/ ;
ClassName Item_2 /*...*/ ;
Like this:
if (Item_1 != Item_2 && Item_1.n_a == Item_2.n_a)
{
//do something
}
Now my Problem is that Item_1.ID and Item_2.ID should be ignored. Is there a easy way to do this? The only solution I came up with is a no brainer of like
if ( (Item_1.n_1 != Item_2.n_1 || Item_1.n_2 != Item_2.n_2 || /* ... */ ) && Item_1.n_a == Item_2.n_a)
Override the object.Equals method in your class and specify how you want it to be compared.
Then use !Item1.Equals(Item2) instead of !=
https://learn.microsoft.com/en-us/dotnet/api/system.object.equals?view=netframework-4.7.2
The easy way is what you are actually doing , just create a method like this
public bool Method(ClassName Item_1,ClassName Item2)
{
bool check=false;
if ( (Item_1.n_1 != Item_2.n_1 || Item_1.n_2 != Item_2.n_2 || /* ... */ ) && Item_1.n_a == Item_2.n_a)
check=true
return check
}
To perform something like Item_1 != Item_2 or Item_1 == Item_2 and get all properties (or the ones you want) to be compared, you need to implement your own Equals method and ==, != operators overloads.
== operator, from MSDN:
For reference types other than string, == returns true if its two operands refer to the same object.
For that you can start with some straightforward solution, to implement IEquatable<T> interface, fill your comparing logic inside Equals method and overload == and != operators internally calling your type-safe Equals method:
public class ClassName : IEquatable<ClassName>
{
public int ID;
public String n_1 { get; set; }
public String n_2 { get; set; }
// ....
public String n_x { get; set; }
public static bool operator ==(ClassName obj1, ClassName obj2)
{
if (((object)obj1) == null || ((object)obj2) == null)
return Equals(obj1, obj2);
return obj1.Equals(obj2);
}
public static bool operator != (ClassName obj1, ClassName obj2)
{
if (((object)obj1) == null || ((object)obj2) == null)
return !Equals(obj1, obj2);
return !obj1.Equals(obj2);
}
public bool Equals(ClassName obj)
{
if (obj == null) return false;
return (n_1 == obj.n_1) && (n_2 == obj.n_2) && (n_x == obj.n_x); //you can ignore ID here
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
ClassName classNameObj = obj as ClassName;
if (classNameObj == null)
return false;
else
return Equals(classNameObj);
}
public override int GetHashCode()
{
//This code was generated by VS ide, you can write your own hashing logic
var hashCode = 1032198799;
hashCode = hashCode * -1521134295 + ID.GetHashCode();
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(n_1);
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(n_2);
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(n_x);
return hashCode;
}
}
Then you can check in your if:
if (Item_1 != Item_2)
{
//Do Something
}
For Equals method you should stick to Guidelines for Overriding Equals() and Operator == .
References: == Operator, != Operator, IEquatable Interface, IEquatable.Equals(T) Method, Guidelines for Overriding Equals() and Operator ==

Reproduce the infinite loop with overriden Equals

Recently I decided to play around with overriding the Equals method. I used mainly the MSDN guideline (the updated one I believe). So my implementation end up like this:
public class EqualityCheck
{
public int Age { get; set; }
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
public override bool Equals(object obj)
{
if (null == obj)
{
return false;
}
//If obj is on of the expected type return false
EqualityCheck ec = obj as EqualityCheck;
if (null == ec)
{
return false;
}
//return true if the fields match. This is the place where we can decide what combination should be unique
return (Age == ec.Age) && (Name == ec.Name) && (DateOfBirth == ec.DateOfBirth);
}
public bool Equals(EqualityCheck ec)
{
// If parameter is null return false:
if (ec == null)
{
return false;
}
// Return true if the fields match:
return (Age == ec.Age) && (Name == ec.Name);
}
//How to implement GetHashCode for complex object?
}
And also one child class:
public class EqualityCheckChild : EqualityCheck
{
public int Height { get; set; }
public override bool Equals(System.Object obj)
{
// If parameter cannot be cast to ThreeDPoint return false:
EqualityCheckChild ec1 = obj as EqualityCheckChild;
if (ec1 == null)
{
return false;
}
// Return true if the fields match:
return base.Equals(obj) && Height == ec1.Height;
}
public bool Equals(EqualityCheckChild ec1)
{
// Return true if the fields match:
return base.Equals((EqualityCheck)ec1) && Height == ec1.Height;
}
public static bool operator ==(EqualityCheckChild a, EqualityCheckChild b)
{
if (Equals(a, b))
{
return true;
}
if (a == null || b == null)
{
return false;
}
return a.DateOfBirth == b.DateOfBirth && a.Name == b.Name;
}
public static bool operator !=(EqualityCheckChild a, EqualityCheckChild b)
{
return !(a == b);
}
}
I think this is what MSDN shows as implementation, just with removed casts.
I am using VS2015 and .NET 4.5.2. VS marked the casting as redundant, that's when I look up what's the issue with this. I've read about the possible infinity loop and just out of curiosity I decided to recreate it with the code above. However I can't reproduce it.
Since this is not copy-paste code. At least not literally. I wrote it by hand trying to understand what I am doing so I guess it's possible to have some mismatch with the original code which leads to this. But still my question remains - how to reproduce the problem which is also mentioned in the MSDN article?
Attempt to compare an instance of EqualityCheckChild to null.
EqualityCheckChild foo = new EqualityCheckChild();
Console.WriteLine(foo == null);
This code snippet will cause a StackOverflowException, because in the operator== method, if (a == null || b == null) calls itself.

Using equality comparer in lambda expression

I have a Venue class, and a Coordinate class like so:
class Venue
{
string Name;
Coordinate coordinate;
}
class Coordinate
{
double latitute;
double longitude;
}
Now, I want to be able to select a venue based on a coordinate as follows:
List<Venue> venues = GetAllVenues();
var myVenue = venues.FirstOrDefault(venue=>venue.coordinate == myCoordinate);
I have an IEqualityComparer implementation, but the lambda expression does not have an overload which takes the IEqualityComparer as a parameter.
How do I use my equality comparer in a lambda expression?
EDIT:
My equality comparer looks like this:
class CoordinatesEqualityComparer:IEqualityComparer<Coordinate>
{
public bool Equals(Coordinate x, Coordinate y)
{
return x.RowIndex == y.RowIndex && x.ColumnIndex == y.ColumnIndex;
}
public int GetHashCode(Coordinate obj)
{
return obj.GetHashCode();
}
}
When I do a Union() operation, like so, it does not work correctly, even though coordinates in both lists are same.
List<Coordinates> coordinates;
CoordinatesEqualityComparer comparer;
coordinates.Union(someOtherListOfCoordinates, comparer);
However, when I do a union with itself, it works. What am I doing wrong? Does it have something to do with the GetHashCode() implementation?
Edit 2:
Fixing the GetHashCode() method seems to do the trick.
public int GetHashCode(Coordinates obj)
{
// Warning:Hack. Use two prime numbers to generate a hash based on two properties.
return obj.RowIndex.GetHashCode() * 7 + obj.ColumnIndex.GetHashCode() * 13 ;
}
Have you tried:
var ec = new YourEqualityComparer();
var myVenue = venues.FirstOrDefault(venue =>
ec.Equals(venue.coordinate, myCoordinate));
Of course, another approach would be to define the == operator for your Coordinate class and then you wouldn't need an IEqualityComparer:
class Coordinate
{
double latitude;
double longitude;
public override bool Equals(object obj)
{
return Object.ReferenceEquals(this, obj)) ||
this == (other as Coordinate);
}
public static bool operator ==(Coordinate l, Coordinate r)
{
return ((object)l == null && (object)r == null) ||
((object)l != null && (object)r != null) &&
// equality check including epsilons, edge cases, etc.
}
public static bool operator !=(Coordinate l, Coordinate r)
{
return !(l == r);
}
}
I would implement IEquatable<Coordinate>, override Equals(object), override GetHashCode(), and == != operators like this:
public class Coordinate : IEquatable<Coordinate>
{
public double Latitide { get; set; }
public double Longitude { get; set; }
public bool Equals(Coordinate other)
{
if (other == null)
{
return false;
}
else
{
return this.Latitide == other.Latitide && this.Longitude == other.Longitude;
}
}
public override bool Equals(object obj)
{
return this.Equals(obj as Coordinate);
}
public override int GetHashCode()
{
return this.Latitide.GetHashCode() ^ this.Longitude.GetHashCode();
}
public static bool operator ==(Coordinate value1, Coordinate value2)
{
if (!Object.ReferenceEquals(value1, null) && Object.ReferenceEquals(value2, null))
{
return false;
}
else if (Object.ReferenceEquals(value1, null) && !Object.ReferenceEquals(value2, null))
{
return false;
}
else if (Object.ReferenceEquals(value1, null) && Object.ReferenceEquals(value2, null))
{
return true;
}
else
{
return value1.Latitide == value2.Latitide && value1.Longitude == value2.Longitude;
}
}
public static bool operator !=(Coordinate value1, Coordinate value2)
{
return !(value1 == value2);
}
}

Categories