【发布时间】:2019-06-05 20:12:26
【问题描述】:
考虑:
class Base : IEquatable<Base> {
public bool Equals(Base other) => false;
public override bool Equals(Object o) => false;
public override int GetHashCode() => 0;
public static bool operator ==(Base o1, Base o2) => Equals(o1, o2);
public static bool operator !=(Base o1, Base o2) => !Equals(o1, o2);
}
class Derived : Base {
public static bool operator ==(Derived o1, Derived o2) => Equals(o1, o2);
public static bool operator !=(Derived o1, Derived o2) => !Equals(o1, o2);
}
我明白了:
Warning CS0660 'Derived' defines operator == or operator != but does not override Object.Equals(object o)
Warning CS0661 'Derived' defines operator == or operator != but does not override Object.GetHashCode()
这些警告对我来说是错误的 - 因为我从 Base 继承了被覆盖的 Equals(object) 和 GetHashCode(),所以代码不应该有任何警告。
而且没有什么好办法——
我可以实现Derived中丑陋而多余的功能
我可以添加#pragma warning disable CS0660, CS0661,但这将禁用文件中各处的警告,不仅是在安全派生函数的位置。
这是对 C# 编译器的疏忽还是有充分的理由? 有没有干净的方法?
【问题讨论】:
-
为什么编译器应该假设
Base上的Equals以与Derived上的operator==相关的任何方式实现逻辑?事实上,在没有另一个的情况下实现一个通常是错误的,因为比较Derived的逻辑可能比Base中的Equals做得更多。 -
不,我认为这是正确的。如果
Base实现了运算符,那么这将被认为是正确的,但是由于Derived可能使用Base.Equals无法获得的信息,编译器不能假设它是Derived.operator ==的适当匹配项,尽管如果你定义了它们就Base.Equals而言应该,但是太复杂了。只需添加将Derived.Equals定义为Base.Equals的覆盖:public override bool Equals(object o) => base.Equals(o);和GetHashCode相同。 -
在派生类中重载操作符的唯一原因是你想改变行为。如果您不打算改变行为,那么不要重载运算符,让基类的重载来完成它的工作。
-
@kofifus 他问的问题和你差不多,他也可以像你一样争论为什么他会收到这个警告,因为他继承了
Equals(object)和GetHashCode()来自ValueType -
@kofifus 静态成员是继承的,如果你想要技术的话。并不是说在这种情况下它真的很重要。操作符重载是存在的,调用的时候会发现,这才是最重要的。
标签: c#