Это пример того, что я пытаюсь сделать:
public class Foo : IEquatable<Foo>
{
    public bool Equals(Foo other)
    {
        Type type1 = this.GetType();
        Type type2 = other.GetType();
        if (type1 != type2)
            return false;
        if (type1 == typeof(A))
        {
            A a = (A)this;
            A b = (A)other;
            return a.Equals(b);
        }
        else if (type1 == typeof(B))
        {
            B c = (B)this;
            B d = (B)other;
            return c.Equals(d);
        }
        else
        {
            throw new Exception("Something is wrong");
        }
    }
}
public class A : Foo, IEquatable<A>
{
    public int Number1 { get; set; }
    public int Number2 { get; set; }
    public bool Equals(A other)
    {
        return this.Number1 == other.Number1 && this.Number2 == other.Number2;
    }
}
public class B : Foo, IEquatable<B>
{
    public int Number1 { get; set; }
    public int Number2 { get; set; }
    public int Number3 { get; set; }
    public bool Equals(B other)
    {
        return this.Number1 == other.Number1 && this.Number2 == other.Number2 && this.Number3 == other.Number3;
    }
}
Но, как вы можете видеть выше, мне пришлось бы использовать множество условных выражений "if" для идентификации реального типа. Проблема в том, что я должен использовать базовый класс. Например:
A a = new A();
Foo foo = a;
foo.Equals(another);