Pieter Geerkens
Pieter Geerkens

Reputation: 11883

Implementing == operator in C# on explicit-interface implementation

I have defined a struct Coords that explicitly implements three interfaces, each defined like this:

  public partial struct Coords
  {
    int           ICoordsUser.X          { get { return VectorUser.X; } }
    int           ICoordsUser.Y          { get { return VectorUser.Y; } }
    IntVector2D   ICoordsUser.Vector     { get { return VectorUser;   }
                                           set { VectorUser=value;    } }
    ICoordsCanon  ICoordsUser.Canon      { get { return this;         } } 
    ICoordsUser   ICoordsUser.Clone()    { return NewUserCoords(VectorUser);  }
    string        ICoordsUser.ToString() { return VectorUser.ToString(); }

    IEnumerable<NeighbourCoords> ICoordsUser.GetNeighbours(Hexside hexsides) { 
        return GetNeighbours(hexsides); 
    }
    int ICoordsUser.Range(ICoordsUser coords) { return Range(coords.Canon); }
  }

with the names ICoordsCanon, ICoordsUser, and ICoordsCustom. Then I have defined Value Equality on the struct like so:

#region Value Equality
bool IEquatable<Coords>.Equals(Coords rhs) { return this == rhs; }

public override bool Equals(object rhs) { 
  return (rhs is Coords) && this == (Coords)rhs; 
}

public static bool operator == (Coords lhs, Coords rhs) { 
  return lhs.VectorCanon == rhs.VectorCanon; 
}

public static bool operator != (Coords lhs, Coords rhs) { return ! (lhs == rhs); }
public override int GetHashCode() { return VectorUser.GetHashCode(); }

bool IEqualityComparer<Coords>.Equals(Coords lhs, Coords rhs) { return lhs == rhs; }
int  IEqualityComparer<Coords>.GetHashCode(Coords coords) {
    return coords.GetHashCode();
}
#endregion

However, when I perform an equality comparison with the == operator between values of one of the interface types, as

if (coordsUser1 == userCoords2) { /* whatever */ }

a reference comparison using object.== is always performed. Does anyone know how I can force value equality onto the == operator in such a circumstance, using C#?

Thank you in advance for any thoughts or suggestions.

[Edit] In the example above, both coordsUser1 and userCoords2 are instances of Coords stored in variables of type ICoordsUser, so it is not clear to me why the defined override of == is not being used.

Upvotes: 1

Views: 406

Answers (1)

Daniel A.A. Pelsmaeker
Daniel A.A. Pelsmaeker

Reputation: 50326

Since you cannot define static members for an interface, you cannot define operators on an interface. Because operator overloading is resolved at compile-time, the compiler will not see any == operator that matches the signature given an interface type. Since Object defines the == operator for objects, and there is no better match at compile time, it will use that one.

There are three ways to solve this:

  1. Cast the left-hand object to the type that defines the == operator.

    return (Coords)coordsUser1 == userCoords2;
    
  2. Use the normal Equals(object) method. However, this will box your struct.

    return coordsUser1.Equals(userCoords2);
    
  3. Force your interfaces to implement IEquatable<T>, and use the generic Equals(T) (which reduces boxing).

    return coordsUser1.Equals(userCoords2);
    

Upvotes: 5

Related Questions