C# Equals方法继承混乱

C# Equals方法继承混乱,c#,inheritance,C#,Inheritance,假设我有一个类,ClassB,它通过添加另一个不在ClassA中的属性来扩展另一个类,ClassA。以下方法有效吗 public bool Equals(ClassB other) { return this.ExtraProp == other.ExtraProp && base.Equals(ClassB); } 为什么应该允许我将ClassB对象传递给ClassA的equals方法(只接受ClassA对象)?继承就是这样工作的吗?因为ClassB对象是ClassA

假设我有一个类,
ClassB
,它通过添加另一个不在
ClassA
中的属性来扩展另一个类,
ClassA
。以下方法有效吗

public bool Equals(ClassB other)
{
    return this.ExtraProp == other.ExtraProp && base.Equals(ClassB);
}

为什么应该允许我将
ClassB
对象传递给
ClassA
的equals方法(只接受
ClassA
对象)?继承就是这样工作的吗?

因为
ClassB
对象是
ClassA
对象。您可以在任何地方将
ClassB
对象视为
ClassA
对象。这就是多态性的本质

至于它是否会实际返回正确的结果,这将取决于
ClassA
的实现。某些实现不会像代码所期望的那样工作,但其他实现会

让我们在这里用一个具体的例子。假设这是
ClassA
的定义:

public class ClassA
{
    public int first;
    public int second;
    public bool Equals(ClassA other)
    {
        if (other == null) return false;
        return first == other.first &&
            second == other.second;
    }
}
现在让我们假设我们有这些对象:

ClassA a = new ClassA() { first = 1, second = 2 };
ClassB b = new ClassB() { first = 1, second = 2, third = 3 };
此处
a.Equals(b)
将为
true
。它有两个被检查的属性,因此它认为它们相等。您希望这些对象被视为相等吗

另一种实施方式是:

public bool Equals(ClassA other)
{
    if (other == null) return false;
    if (other.GetType() != typeof(ClassA)) return false;
    return first == other.first &&
        second == other.second;
}

这里我们显式地检查(在运行时而不是在编译时授予)以确保另一个实例不是更派生的类型。在这种情况下,
a.Equals(b)
将为false。您可以实现您喜欢的任何语义。

因为
ClassB
对象是
ClassA
对象。您可以在任何地方将
ClassB
对象视为
ClassA
对象。这就是多态性的本质

至于它是否会实际返回正确的结果,这将取决于
ClassA
的实现。某些实现不会像代码所期望的那样工作,但其他实现会

让我们在这里用一个具体的例子。假设这是
ClassA
的定义:

public class ClassA
{
    public int first;
    public int second;
    public bool Equals(ClassA other)
    {
        if (other == null) return false;
        return first == other.first &&
            second == other.second;
    }
}
现在让我们假设我们有这些对象:

ClassA a = new ClassA() { first = 1, second = 2 };
ClassB b = new ClassB() { first = 1, second = 2, third = 3 };
此处
a.Equals(b)
将为
true
。它有两个被检查的属性,因此它认为它们相等。您希望这些对象被视为相等吗

另一种实施方式是:

public bool Equals(ClassA other)
{
    if (other == null) return false;
    if (other.GetType() != typeof(ClassA)) return false;
    return first == other.first &&
        second == other.second;
}

这里我们显式地检查(在运行时而不是在编译时授予)以确保另一个实例不是更派生的类型。在这种情况下,
a.Equals(b)
将为false。您可以实现您喜欢的任何语义。

Employee
继承自
Human

Employee
的属性不仅仅是
,但它仍然是


如果你实现了一个
Human.Equals()
你可以传递一个
员工
,因为在内心深处
员工
仍然是
。。。。但是你不能像对待员工一样对待人类,因为不是所有的人类都有收入属性

Employee
的属性不仅仅是
,但它仍然是


如果你实现了一个
Human.Equals()
你可以传递一个
员工
,因为在内心深处
员工
仍然是
。。。。但你不能像对待员工一样对待人类,因为并非所有人类都具有多态性的收入属性。这也是Liskov替代原理的作用=)+1。很好的解释。但在这里你必须小心。如果重写
ClassB.Equals
,则可以得到如下情况:A.Equals(B)==true和
B.Equals(A)==false
。这可能非常令人困惑。正如您所说,这取决于您喜欢的语义。我被烧坏的次数已经够多了,所以我更喜欢您的第二个实现:两个对象不相等,除非它们是相同的类型。如果我需要继承的类型作为相等进行比较,我将为多态性创建一个自定义相等比较器。+1。这也是Liskov替代原理的作用=)+1。很好的解释。但在这里你必须小心。如果重写
ClassB.Equals
,则可以得到如下情况:A.Equals(B)==true和
B.Equals(A)==false
。这可能非常令人困惑。正如您所说,这取决于您喜欢的语义。我被烧坏的次数已经够多了,所以我更喜欢您的第二个实现:两个对象不相等,除非它们是相同的类型。如果我需要继承的类型作为相等进行比较,我将创建一个自定义相等比较器。