Implementasi kesetaraan generik untuk kelas turunan

Saya ingin objek yang menurunkan kelas tertentu A juga memperoleh implementasi Equals(A other) yang akan melakukan hal berikut: jika tipe this dan other berbeda, kembalikan false, jika tidak, kembalikan this.value == other.value.

Upaya saya terlihat seperti ini:

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));
    }
}

Ini berfungsi dengan baik sampai kita mendapatkan lebih banyak:

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

    }
}

lalu rusak:

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

dan sekarang aku terjebak. Bagaimana cara membuatnya berhasil? Memperbaiki implementasi agar berfungsi dengan lebih dari satu tingkat warisan dan mencegah lebih dari satu tingkat warisan dapat diterima.

Namun saya mengerti bahwa saya hanya perlu mendeklarasikan semua keturunan tingkat pertama A<T> sebagai tersegel, tapi itu adalah pilihan terakhir kecuali jika itu dapat ditegakkan (sehingga keturunan A<T> yang tidak tersegel akan menyebabkan kesalahan kompilasi). Atau mungkin pendekatan saya salah total?


person n0rd    schedule 28.04.2018    source sumber


Jawaban (1)


Ini semua karena operator as dapat mengubah subkelas menjadi superkelas tanpa masalah.

Yang ingin Anda lakukan adalah memeriksa tipenya dan melihat apakah keduanya sama:

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

pertanyaan ini agak terkait, tentang perilaku GetType, typeof dan is , yang cara kerjanya mirip dengan as.

person Sweeper    schedule 28.04.2018
comment
Saya curiga saya terlalu memikirkannya. Ini berhasil, tetapi saya akan menunggu sebentar untuk jawaban lain sebelum menerimanya. - person n0rd; 28.04.2018
comment
Maka tidak perlu membuat kelas A menjadi generik. - person Cheng Chen; 28.04.2018
comment
@DannyChen Dari apa yang OP tunjukkan, A tidak perlu generik sama sekali, tapi ini bukan kode lengkap OP, jadi saya berasumsi bahwa OP menggunakan parameter generik di tempat lain. - person Sweeper; 28.04.2018