Search code examples
c#genericsiequatable

How to implement IEquatable<Container<T>> in C# for all types T?


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.


Solution

  • 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).