سؤال

A domain class T can be of type ValueObject<T>:

public class Coordinate: ValueObject<Coordinate>
{ ... }

ValueObject<T> implements the IEquatable interface. I want each concrete implementation of ValueObject<T> to provide implementation for bool Equals(T obj), so I have created it as an abstract method:

public abstract class ValueObject<T> : IEquatable<T>
{
    public abstract bool Equals(T obj);

    public static bool operator ==(ValueObject<T> obj1, ValueObject<T> obj2)
    {
        if (object.ReferenceEquals(obj1, obj2)) return true;
        if (object.ReferenceEquals(obj1, null)) return false;
        if (object.ReferenceEquals(obj2, null)) return false;

        return obj1.Equals(obj2);
    }
}

An Equals implementation in the Coordinate class:

public class Coordinate : ValueObject<Coordinate>
{
    // ...

    public override bool Equals(Coordinate other)
    {
        return (other != null) && (this.Latitude == other.Latitude) && (this.Longitude == other.Longitude);
    }
}

ValueObject<T> provides generic operating overriding for == (and for !=, which is not shown above), which applies to all concrete implementations.

The problem is that when the Equals method is called from either the == override, it calls Object.Equals() and not Coordinate.Equals().

هل كانت مفيدة؟

المحلول

The problem is that when the Equals method is called from either the == override, it calls Object.Equals() and not Coordinate.Equals().

No, the problem is that those things are different. If they are the same, as they should be, then there's no problem.

So make them the same. Don't make the derived class do the wrong thing; force them to do the right thing.

public abstract class ValueObject<T> : IEquatable<T>
{
    // Force the derived class to override these.
    public abstract override bool Equals(object obj);
    public abstract override int GetHashcode(object obj);

    // And then consistently use the overridden method as the implementation.
    public virtual bool Equals(T obj)
    {
        return obj1.Equals((object)obj2);
    }
    public static bool operator ==(ValueObject<T> obj1, ValueObject<T> obj2)
    {
         return obj1.Equals((object)obj2);
    }
    public static bool operator !=(ValueObject<T> obj1, ValueObject<T> obj2)
    {
         return !obj1.Equals((object)obj2);
    }
}

نصائح أخرى

When you say obj1.Equals(obj2), obj2 is of type ValueObject<T> which does not match the T in public abstract bool Equals(T obj).

In fact, at runtime it could be of a different class than T.

Probably, you want to return false in that case.

public static bool operator ==(ValueObject<T> obj1, ValueObject<T> obj2)
{
    if (object.ReferenceEquals(obj1, obj2)) return true;
    if (object.ReferenceEquals(obj1, null)) return false;
    if (object.ReferenceEquals(obj2, null)) return false;
    if (obj1.GetType() != obj2.GetType()) return false; //new

    return ((T)(object)obj1).Equals((T)(object)obj2);
}

I think you indend that T is equal to a derived class of ValueObject<T>. You can say where T : ValueObject<T>. That encodes at least a part of what you want in the type system and saves you the (object) cast.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top