Abstract class to implement equality operators - c#

Lets say I define the following abstract class:
public abstract class ValueEquality<T> : IEquatable<T>
where T : ValueEquality<T>
{
public override bool Equals(object obj)
{
return Equals(obj as T);
}
public static bool operator ==(ValueEquality<T> lhs, object rhs)
{
if (ReferenceEquals(lhs, rhs))
{
return true;
}
else if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null))
{
return false;
}
else
{
return lhs.Equals(rhs);
}
}
public static bool operator !=(ValueEquality<T> lhs, object rhs)
{
return !(lhs == rhs);
}
public bool Equals(T other)
{
return other != null && EqualNoNull(other);
}
public abstract override int GetHashCode();
public abstract bool EqualNoNull(T other);
}
And then create a class C as follows:
public class C : MyEquatable<C>
{
public override bool EqualsNoNull(C other)
{
...
}
public override int GetHashCode()
{
...
}
}
If I then have the code:
C x1;
C x2;
bool equal = x1 == x2;
Will this end up calling the equals method in C? Are there any gotchas with this approach?
Edit: fixed some issues in code raised by answers.

This code will do infinite loop in:
public override bool Equals(object obj)
{
try
{
T otherT = (T) obj;
return Equals(this, otherT);
}
catch (InvalidCastException)
{
return false;
}
}
It will call Equals(object obj) again and again. Right implementation:
public abstract class MyEquatable<T> : IEquatable<T>
where T : MyEquatable<T>
{
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != this.GetType())
{
return false;
}
return this.Equals((MyEquatable<T>)obj);
}
protected bool Equals(MyEquatable<T> other)
{
return this.Equals(other as T);
}
public static bool operator ==(MyEquatable<T> lhs, object rhs)
{
return Equals(lhs, rhs);
}
public static bool operator !=(MyEquatable<T> lhs, object rhs)
{
return Equals(lhs, rhs);
}
public abstract bool Equals(T other);
public abstract override int GetHashCode();
}
x1 == x2 will call operator == of MyEquatable, that will call Equals(object obj). Finally, it calls Equals(T other) overridden in C class

Another implementation which follows what is usually advised in documentation
public abstract class MyEquatable<T> : IEquatable<T>
where T : MyEquatable<T> {
public override bool Equals(object obj) {
if (ReferenceEquals(obj, null) || obj.GetType() != GetType())
return false;
var valueObject = obj as T; //Note the cast
if (ReferenceEquals(valueObject, null))
return false;
return Equals(valueObject); //Calls Equals(T other)
}
public abstract bool Equals(T other);
public abstract override int GetHashCode();
public static bool operator ==(MyEquatable<T> left, MyEquatable<T> right) {
if (ReferenceEquals(left, null) && ReferenceEquals(right, null))
return true;
if (ReferenceEquals(left, null) || ReferenceEquals(right, null))
return false;
return left.Equals(right);
}
public static bool operator !=(MyEquatable<T> left, MyEquatable<T> right) {
return !(left == right);
}
}

Related

Possible null reference in IEquatable implementation

I'm trying to find out how to remove that possible null reference in the IEquatable implementation below.
return other != null && _guid == other._guid; Possible null reference argument for parameter 'left' in 'bool SubscriptionToken.operator !=(SubscriptionToken left, SubscriptionToken right)'
public class SubscriptionToken : IEquatable<SubscriptionToken>
{
public static readonly SubscriptionToken Empty = new(Guid.Empty);
private readonly Guid _guid;
private SubscriptionToken(Guid guid)
{
_guid = guid;
}
private SubscriptionToken()
{
}
public Guid Value => _guid;
public bool Equals(SubscriptionToken? other)
{
return other != null && _guid == other._guid; // Possible null reference
}
public bool IsValid()
{
return _guid != Guid.Empty;
}
public static SubscriptionToken New()
{
return new SubscriptionToken(Guid.NewGuid());
}
public override bool Equals(object? other)
{
return other is SubscriptionToken token && Equals(token);
}
public override int GetHashCode()
{
return HashCode.Combine(_guid);
}
public override string ToString()
{
return _guid.ToString("N");
}
public static bool operator ==(SubscriptionToken left, SubscriptionToken right)
{
return EqualityComparer<SubscriptionToken>.Default.Equals(left, right);
}
public static bool operator !=(SubscriptionToken left, SubscriptionToken right)
{
return !(left == right);
}
}
Your equals method should probably look something like this:
public bool Equals(SubscriptionToken other)
{
if (ReferenceEquals(null, other)) return false;
return _guid.Equals(other._guid);
}
That should avoid any null reference exceptions.

Substitute IEquatable interface when doing distinct() on a lambda

I have this class which implements the IEquatable<T> interface
public class ArticleDescriptionDetails : IEquatable<ArticleDescriptionDetails>
{
public string Code { get; set; }
public string Value { get; set; }
public bool Hidden { get; set; }
public bool Equals(ArticleDescriptionDetails other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Code == other.Code;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
return obj.GetType() == GetType() && Equals((ArticleDescriptionDetails) obj);
}
public override int GetHashCode() => ((Code != null ? Code.GetHashCode() : 0) * 397) ^ Hidden.GetHashCode();
public static bool operator ==(ArticleDescriptionDetails left, ArticleDescriptionDetails right) => Equals(left, right);
public static bool operator !=(ArticleDescriptionDetails left, ArticleDescriptionDetails right) => !Equals(left, right);
}
I need this beacuse I'm tring to return an IEquatable<ArticleDescriptionDetails> in this way:
return result.OrderBy(x => x.Code).ThenBy(y => y.Hidden).Distinct();
Is there a way to do the same thing without using the IEquatable<T> interface?
You could use a DistinctBy method and do
return result.OrderBy(x => x.Code).ThenBy(y => y.Hidden).DistinctBy(z => z.Code);
But the DistinctBy method doesn't exist in linq but you can find it in the morelinq package https://www.nuget.org/packages/MoreLinq.Source.MoreEnumerable.DistinctBy/
But it's also easy to code your own version of the method :
You first need to define an IEqualityComparer
public class KeyEqualityComparer<T, K> : IEqualityComparer<T>
{
private readonly Func<T, K> selector;
public KeyEqualityComparer(Func<T, K> keySelector)
{
selector = keySelector;
}
public bool Equals(T x, T y)
{
return selector(x).Equals(selector(y));
}
public int GetHashCode(T obj)
{
return selector(obj).GetHashCode();
}
}
And the you can use this IEqualityComparer in the Distinct method :
public static IEnumerable<T> DistinctBy<T, K>(this IEnumerable<T> list, Func<T, K> keySelector)
{
var equalityComparer = new KeyEqualityComparer<T, K>(keySelector);
return list.Distinct(equalityComparer);
}

C# How to call overloaded operator in generic parent class?

Following problem:
In the definition of an function of a generic parent class ParentA I want to call an overloaded operator from ChildB:
See the following structure
class ParentA<T> where T : ParentB
{
public bool Contains(T element)
{
T element2;
return element==element2;
}
}
class ChildB : ParentB
{
public static bool operator ==(ChildB s1, ChildB s2)
{
//this one should be used
}
}
ChildA :ParentA<ChildB>
{
//make use of inherited function Contains(ChildB element)
}
I want to call the overloaded == operator of ChildB, but instead when I call the Contains function in ChildA the original ==operator from ParentB will be called.
Any idea how to make this work?
The Original code is a bit more nasty
public abstract class ElementBase
{
protected Element element;
public Element Element
{
get { return element; }
set { element = value; }
}
public static bool operator ==(ElementBase e1, ElementBase e2)
{
return e1.element == e2.element;
}
public static bool operator !=(ElementBase e1, ElementBase e2)
{
return e1.element != e2.element;
}
public override bool Equals(object obj)
{
if ((obj == null) || !this.GetType().Equals(obj.GetType()))
return false;
else
{
ElementBase element = (ElementBase)obj;
return this == element;
}
}
}
public class Structure : ElementBase
{
public bool flag;
public static bool operator ==(Structure s1, Structure s2)
{
return s1.element == s2.element && s1.flag==s2.flag;
}
public static bool operator !=(Structure s1, Structure s2)
{
return s1.element != s2.element || s1.flag!=s2.flag;
}
public override bool Equals(object obj)
{
if ((obj == null) || !this.GetType().Equals(obj.GetType()))
return false;
else
{
Structure structure = (Structure)obj;
return this == structure;
}
}
}
public class MapBase<T> where T : ElementBase
{
protected Dictionary<long, T> elements = new Dictionary<long, T>();
public bool Contains(T element)
{
...
return element==elements[id];
}
}
public class StructureMap : MapBase<Structure>
{
void someFunction()
{
//make use of Contains(Structure element)
}
}
Update
I replaced
return element==element2;
by
return element.Equals(element2);
and now it seems like it does the trick. I just don't understand why...

If I understand correctly: C# Equality operator ( == ) and order of operands

Similar questions have been asked, but I'm not sure I understand the answers correctly. I am referring to a situation where the equality operator is overridden in one or both classes. Please explain if I'm right. If I write if(a == b) { ... }, then equality operator of the class of "a" is used and in case of if(b == a) { ... } is used then equality operator defined in the class of "b". The equality operator of which class is used if I write if(null == a) { ... }.
situation where the equality operator is overridden in one or both classes
We can do that and test... something like the following?
class A
{
public static bool operator == (A a, B b)
{
Console.WriteLine("A");
return false;
}
public static bool operator != (A a, B b)
{
Console.WriteLine("A");
return false;
}
public static bool operator == (B b, A a)
{
Console.WriteLine("A");
return false;
}
public static bool operator != (B b, A a)
{
Console.WriteLine("A");
return false;
}
public override bool Equals(object o)
{
return false;
}
public override int GetHashCode()
{
return 0;
}
}
class B
{
public static bool operator == (A a, B b)
{
Console.WriteLine("B");
return false;
}
public static bool operator != (A a, B b)
{
Console.WriteLine("B");
return false;
}
public static bool operator == (B b, A a)
{
Console.WriteLine("B");
return false;
}
public static bool operator != (B b, A a)
{
Console.WriteLine("B");
return false;
}
public override bool Equals(object o)
{
return false;
}
public override int GetHashCode()
{
return 0;
}
}
Then you write code such as:
A a = new A();
B b = new B();
if (a == b)
{
// ...
}
Then you get:
CS0034 Operator '==' is ambiguous on operands of type 'A' and 'B'
Does that answer your question? Have a look at the code, when you define the operator == you specify the types of the parameters, and the compiler uses that to choose the operator to call. In this case it finds two operators that have operands A and B in that order and that results in an ambiguous call (the compiler does not know - does not have a way to decide - which one to use).
If I write if(a == b) { ... }, then equality operator of the class of "a" is used and in case of if(b == a) { ... } is used then equality operator defined in the class of "b"
That depends on the types of the operands. If you always put the operant of the type of the current class as first, then that is true. For example:
void Main()
{
A a = new A();
B b = new B();
if (a == b)
{
// ...
}
}
class A
{
public static bool operator == (A a, B b)
{
Console.WriteLine("A");
return false;
}
public static bool operator != (A a, B b)
{
Console.WriteLine("A");
return false;
}
public override bool Equals(object o)
{
return false;
}
public override int GetHashCode()
{
return 0;
}
}
class B
{
public static bool operator == (B b, A a)
{
Console.WriteLine("B");
return false;
}
public static bool operator != (B b, A a)
{
Console.WriteLine("B");
return false;
}
public override bool Equals(object o)
{
return false;
}
public override int GetHashCode()
{
return 0;
}
}
Output: A.
However, if define the operators with the operands in the opposite order...
void Main()
{
A a = new A();
B b = new B();
if (a == b)
{
// ...
}
}
class A
{
public static bool operator == (B b, A a)
{
Console.WriteLine("A");
return false;
}
public static bool operator != (B b, A a)
{
Console.WriteLine("A");
return false;
}
public override bool Equals(object o)
{
return false;
}
public override int GetHashCode()
{
return 0;
}
}
class B
{
public static bool operator == (A a, B b)
{
Console.WriteLine("B");
return false;
}
public static bool operator != (A a, B b)
{
Console.WriteLine("B");
return false;
}
public override bool Equals(object o)
{
return false;
}
public override int GetHashCode()
{
return 0;
}
}
Output: B.
The equality operator of which class is used if I write if(null == a) { ... }
First, let us be clear. B or any other classes are irrelevant here. They do not affect the outcome of this comparison, because you are not using them here. It would be very inconvenient if they did.
Let us try:
void Main()
{
A a = new A();
if (null == a)
{
// ...
}
}
class A
{
public static bool operator == (A a, B b)
{
Console.WriteLine("A");
return false;
}
public static bool operator != (A a, B b)
{
Console.WriteLine("A");
return false;
}
public override bool Equals(object o)
{
return false;
}
public override int GetHashCode()
{
return 0;
}
}
class B
{
public static bool operator == (B b, A a)
{
Console.WriteLine("B");
return false;
}
public static bool operator != (B b, A a)
{
Console.WriteLine("B");
return false;
}
public override bool Equals(object o)
{
return false;
}
public override int GetHashCode()
{
return 0;
}
}
Output: .
We get no output, because the called operator is none of the ones defined here... intead it is using the default operator (the one for object).
Wait! What if I change the order of operands?
void Main()
{
A a = new A();
if (null == a)
{
// ...
}
}
class A
{
public static bool operator == (B b, A a)
{
Console.WriteLine("A");
return false;
}
public static bool operator != (B b, A a)
{
Console.WriteLine("A");
return false;
}
public override bool Equals(object o)
{
return false;
}
public override int GetHashCode()
{
return 0;
}
}
class B
{
public static bool operator == (A a, B b)
{
Console.WriteLine("B");
return false;
}
public static bool operator != (A a, B b)
{
Console.WriteLine("B");
return false;
}
public override bool Equals(object o)
{
return false;
}
public override int GetHashCode()
{
return 0;
}
}
Output: A.
Now we are using the operator on A because it matches the operand types better than the default operator does.
Simply try it out.
public class Program
{
public static void Main()
{
var foo = new Foo();
if(foo == null)
{
}
if(null == foo)
{
}
}
}
public class Foo
{
public static bool operator ==(Foo a, Foo b)
{
Console.WriteLine("Foo operator == called");
return ReferenceEquals(a, b);
}
public static bool operator !=(Foo a, Foo b)
{
Console.WriteLine("Foo operator != called");
return !(a == b);
}
public override bool Equals(object obj)
{
Console.WriteLine("Foo Equals() called");
return ReferenceEquals(this, obj);
}
public override int GetHashCode()
{
Console.WriteLine("Foo GetHashCode() called");
return base.GetHashCode();
}
}
Output:
Foo operator == called
Foo operator == called
So in both cases the equality operator of class Foo will be called.

Implementing equality for 2d lines

I have simple class defining 2d line:
public class Line {
public double X1 { get; set; }
public double Y1 { get; set; }
public double X2 { get; set; }
public double Y2 { get; set; }
}
My primary goal is to get different lines from List using .Distinct(). In my case two lines are equal if theirs coordinates are equal regardless direction (line 1,2 -> 3,4 equals to 3,4 -> 1,2). I going to implement Equals like:
public override bool Equals(object obj) {
if (obj as Line == null) { return false; }
var second = (Line)obj;
if (this.X1 != second.X1 && this.X1 != second.X2) { return false; }
if (this.Y1 != second.Y1 && this.Y1 != second.Y2) { return false; }
if (this.X2 != second.X2 && this.X2 != second.X1) { return false; }
if (this.Y2 != second.Y2 && this.Y2 != second.Y1) { return false; }
return true;
}
but I have no idea how to implement GetHashCode (as I understand it's necessary to make it in case of using Distinct())
This becomes a bit easier if you first define a Point, then define your Line in terms of 2 Points.
Now, to calculate a reliable (but unaffected by direction) hash of a Line, make sure you order your points consistently when calculating the hash.
Putting this all together into a complete implementation (which also covers operator == and !=):
public class Point
{
public double X { get; set; }
public double Y { get; set; }
protected bool Equals(Point other)
{
return X.Equals(other.X) && Y.Equals(other.Y);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Point) obj);
}
public override int GetHashCode()
{
unchecked
{
return (X.GetHashCode()*397) + Y.GetHashCode();
}
}
public static bool operator ==(Point left, Point right)
{
return Equals(left, right);
}
public static bool operator !=(Point left, Point right)
{
return !Equals(left, right);
}
}
public class Line
{
public Point Point1 { get; set; }
public Point Point2 { get; set; }
protected bool Equals(Line other)
{
return Equals(Point1, other.Point1) && Equals(Point2, other.Point2)
|| Equals(Point1, other.Point2) && Equals(Point2, other.Point1);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Line) obj);
}
public override int GetHashCode()
{
unchecked
{
var orderedPoints =
new[] {Point1, Point2}.OrderBy(p => p != null ? p.X : 0)
.ThenBy(p => p != null ? p.Y : 0).ToList();
var p1 = orderedPoints[0];
var p2 = orderedPoints[1];
return ((p1 != null ? p1.GetHashCode() : 0)*397)
+ (p2 != null ? p2.GetHashCode() : 0);
}
}
public static bool operator ==(Line left, Line right)
{
return Equals(left, right);
}
public static bool operator !=(Line left, Line right)
{
return !Equals(left, right);
}
}

Categories

Resources