0

I want objects deriving certain class A to also somehow derive the implementation of the Equals(A other) that would do the following: if types of this and other are different, return false, otherwise return this.value == other.value.

My attempt looks like this:

public class A<T> : IEquatable<A<T>>
    where T: A<T>
{
    protected string Value { get; }
    public A(string value)
    {
        Value = value;
    }

    public bool Equals(A<T> other)
    {
        var concrete = other as T;
        if (concrete == null)
        {
            return false;
        }

        return concrete.Value == Value;
    }
}

public class B : A<B>
{
    public B(string value)
        : base(value)
    {

    }
}

public class C : A<C>
{
    public C(string value)
        : base(value)
    {

    }
}

class Program
{
    static void Main(string[] args)
    {
        var b1 = new B("val");
        var b2 = new B("val");
        var c = new C("val");

        Console.WriteLine(b1.Equals(b1));
        Console.WriteLine(b1.Equals(b2));
        Console.WriteLine(b2.Equals(b1));
        Console.WriteLine(b1.Equals(c));
        Console.WriteLine(b2.Equals(c));
        Console.WriteLine(c.Equals(b1));
        Console.WriteLine(c.Equals(b2));
    }
}

This works fine until we derive more:

public class D : C
{
    public D(string value)
        : base(value)
    {

    }
}

then it breaks:

        var d = new D("val");
        Console.WriteLine(d.Equals(c)); // prints "True"

and now I am stuck. How do I make it work? Both fixing the implementation to work with more than one level of inheritance and preventing more than one level of inheritance are acceptable.

I understand though that I just have to declare all first level descendants of A<T> as sealed, but that's the last resort unless it can be somehow enforced (so non-sealed descendants of A<T> would cause compilation error). Or maybe my approach is wrong completely?

n0rd
  • 11,850
  • 5
  • 35
  • 56

1 Answers1

2

This is all because the as operator can convert subclasses to superclasses without problems.

What you want to do is to check the types and see whether they are equal:

if (this.GetType() == other.GetType()) {
    return false;
}

This question is kind of related, about the behaviours of GetType, typeof and is, which works similar to as.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • I had a suspicion that I was overthinking it. This works, but I'll wait a bit for other answers though before accepting. – n0rd Apr 28 '18 at 07:34
  • Then it's unnecessary to make class `A` generic. – Cheng Chen Apr 28 '18 at 08:02
  • @DannyChen From what OP have shown, `A` doesn't need to be generic at all, but this couldn't be OP's full code, so I assumed that OP used the generic parameter somewhere else. – Sweeper Apr 28 '18 at 08:14