การใช้ความเท่าเทียมกันทั่วไปสำหรับคลาสที่ได้รับ

ฉันต้องการให้อ็อบเจ็กต์ที่ได้รับคลาส A บางตัวได้รับการใช้งาน Equals(A other) ด้วยเช่นกัน ซึ่งจะทำสิ่งต่อไปนี้: หากประเภทของ this และ other แตกต่างกัน ให้ส่งคืน false หรือส่งคืน this.value == other.value

ความพยายามของฉันมีลักษณะเช่นนี้:

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

วิธีนี้ใช้ได้ดีจนกว่าเราจะได้มากกว่านี้:

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

    }
}

แล้วมันพัง:

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

และตอนนี้ฉันติดอยู่ ฉันจะทำให้มันทำงานได้อย่างไร? ทั้งการแก้ไขการใช้งานให้ทำงานกับการสืบทอดมากกว่าหนึ่งระดับและการป้องกันการสืบทอดมากกว่าหนึ่งระดับเป็นสิ่งที่ยอมรับได้

ฉันเข้าใจว่าฉันต้องประกาศลูกหลานระดับแรกทั้งหมดของ A<T> ว่าปิดผนึกแล้ว แต่นั่นเป็นวิธีสุดท้ายเว้นแต่จะสามารถบังคับใช้ได้ด้วยวิธีใดวิธีหนึ่ง (ดังนั้นลูกหลานที่ไม่ได้รับการปิดผนึกของ A<T> จะทำให้เกิดข้อผิดพลาดในการรวบรวม) หรือแนวทางของฉันอาจผิดโดยสิ้นเชิง?


person n0rd    schedule 28.04.2018    source แหล่งที่มา


คำตอบ (1)


ทั้งหมดนี้เป็นเพราะตัวดำเนินการ as สามารถแปลงคลาสย่อยเป็นซูเปอร์คลาสได้โดยไม่มีปัญหา

สิ่งที่คุณต้องการทำคือตรวจสอบประเภทและดูว่าเท่ากันหรือไม่:

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

คำถามนี้มีความเกี่ยวข้องกันเกี่ยวกับพฤติกรรมของ GetType, typeof และ is ซึ่งทำงานคล้ายกับ as

person Sweeper    schedule 28.04.2018
comment
ฉันสงสัยว่าฉันคิดมากเกินไป ใช้งานได้ แต่ฉันจะรอคำตอบอื่นเล็กน้อยก่อนที่จะยอมรับ - person n0rd; 28.04.2018
comment
ถ้าอย่างนั้นก็ไม่จำเป็นต้องสร้างคลาส A ทั่วไป - person Cheng Chen; 28.04.2018
comment
@DannyChen จากสิ่งที่ OP แสดงไว้ A ไม่จำเป็นต้องเป็นแบบทั่วไปเลย แต่นี่ไม่สามารถเป็นโค้ดเต็มของ OP ได้ ดังนั้นฉันจึงสันนิษฐานว่า OP ใช้พารามิเตอร์ทั่วไปที่อื่น - person Sweeper; 28.04.2018