I have a simple, generic container class in C# that looks something like this -
public class Point<T>
{
public T Data { get; }
public string ID { get; }
public Point(T x, string id)
{
this.Data = x;
this.ID = id;
}
}
I would like all Point objects to be compared solely based on the ID
property. My question is - how can I implement IEquatable<Point>
such that any Point objects can be compared to each other? For example, Point<int>
could be compared to Point<decimal>
, and the objects would be considered equal if their ID
properties were identical.
A simple way is to extract a non-generic interface. Though it is not required for IEquatable
, you can even include the Data
property in this interface.
public interface IPoint {
object? Data { get; }
string ID { get; }
}
public class Point<T>: IPoint, IEquatable<IPoint> {
public T Data { get; }
object? IPoint.Data => Data;
public string ID { get; }
public Point(T x, string id) {
this.Data = x;
this.ID = id;
}
public bool Equals(IPoint? other) => ID == other?.ID;
public override bool Equals(object? obj) {
return Equals(obj as IPoint);
}
public override int GetHashCode() {
return ID.GetHashCode();
}
}
Though a caveat is that other code now can provide their own implementation of IPoint
and their own implementation of IEquatable<IPoint>
, that isn't consistent with your Point<T>
. This could cause confusing behaviours such as implA.Equals(implB)
not agreeing with implB.Equals(implA)
.