这有什么错定义的==操作符而不是定义的equals()或GetHashCode()方法?(What&

2019-06-24 21:23发布

对于下面的代码

public struct Person
{
    public int ID;
    public static bool operator ==(Person a, Person b) { return  a.Equals(b); }
    public static bool operator !=(Person a, Person b) { return !a.Equals(b); }
}

为什么编译器给我的这些警告?
出了什么问题如果不定义如下的方法呢?

warning CS0660: 'Person' defines operator == or operator != but
    does not override Object.Equals(object o)

warning CS0661: 'Person' defines operator == or operator != but
    does not override Object.GetHashCode()

Answer 1:

编辑 :这个答案已经被修正,除其他事项需要注意的是用户定义的值类型不产生== ,并与提性能问题ValueType.Equals


在一般情况下,overridding之一,但不是全部,是混乱的。 用户希望既不被覆盖,或者既要,用相同的语义。

微软建议的这个状态(除其他事项外):

  • 实施每当你实现Equals方法GetHashCode方法。 这使得同步的Equals和GetHashCode。

  • 覆盖每当你实现等号(==),并让他们做同样的事情Equals方法。

你的情况,你有正当理由,推迟到Equals (编译器不会自动实现== ),并只覆盖这两个( == / != )。 然而,仍然有性能问题,因为ValueType.Equals使用反射:

“覆盖Equals方法用于特定类型的改善方法的性能和更紧密地代表用于类型相等的概念。”

因此,仍然建议您覆盖所有( == / != / Equals )到底。 当然,性能可能无所谓了这个简单的结构。



Answer 2:

我的猜测是你越来越这些警告,因为编译器不知道你使用Equals==方法

假设你有这样的实现

public struct  Person
{
    public int ID;
    public static bool operator ==(Person a, Person b) { return Math.Abs(a.ID - b.ID) <= 5; }
    public static bool operator !=(Person a, Person b) { return Math.Abs(a.ID - b.ID) > 5; }
}

然后

 Person p1 = new Person() { ID = 1 };
 Person p2 = new Person() { ID = 4 };

 bool b1 = p1 == p2;
 bool b2 = p1.Equals(p2);

B1是真实的 ,但B2

- 编辑 -

现在假设你想这样做

Dictionary<Person, Person> dict = new Dictionary<Person, Person>();
dict.Add(p1, p1);
var x1 = dict[p2]; //Since p2 is supposed to be equal to p1 (according to `==`), this should return p1

但是,这会抛出一个异常,像KeyNotFound

但是,如果你加入

public override bool Equals(object obj)
{
    return Math.Abs(ID - ((Person)obj).ID) <= 5; 
}
public override int GetHashCode()
{
    return 0;
}

你会得到你想要的东西。

编译器只是提醒你,你可以用类似的条件面对



Answer 3:

还有的是,框架内的普遍期待某些操作应始终产生相同的结果。 其原因是,某些操作(具体地,排序和搜索,从而弥补了任何应用程序的大部分)依靠产生有意义且一致的结果这些不同的操作。 在这种情况下,你破坏了一对夫妇的假设:

  • 如果有一个有效的操作==之间ab ,它应产生相同的结果a.Equals(b)
  • 类似的,如果有一个有效的操作!=之间的ab ,它应该产生相同的结果!a.Equals(b)
  • 如果两个对象ab存在,其a == b ,那么ab应存储在哈希表时产生相同的密钥。

前两个,国际海事组织,是显而易见的; 如果要定义什么意思两个对象是相等的,你应该包括所有你可以检查两个对象是相等的方式。 需要注意的是,编译器不会(在一般情况下, 不能 )强制执行,你实际上遵循这些规则。 它不会执行操作员的身体的复杂的代码分析,看看他们是否已经模仿Equals ,因为在最坏的情况下,这可能是等同于解决停机问题。

它可以做什么,但是,是检查,你最有可能正在打破这些规则,特别是您提供自定义比较运营商并没有提供自定义的情况下Equals方法。 这里的假设是,你会不会都不屑于为运营商提供,如果你不希望他们做一些特别的东西,在这种情况下,你应该为所有需要被同步的方法提供自定义行为。

如果你没有实现Equals被什么东西从不同的==编译器不会抱怨; 你会打的难C#怎么愿意尝试阻止你做一些愚蠢的限制。 它愿意在你的代码不小心引入微妙的错误阻止你,但它会让你故意这样做,如果这就是你想要的。

第三个假设是与事实是框架中的许多内部操作使用哈希表的一些变种做。 如果我有两个目标是,通过我的定义,“平等”,那么我应该能够做到这一点:

if (a == b)
{
    var tbl = new HashTable();
    tbl.Add(a, "Test");

    var s = tbl[b];
    Debug.Assert(s.Equals("Test"));
}

这是哈希表,如果它突然变得不正确,会导致非常奇怪的问题的基本性质。



Answer 4:

所有你需要做的就是添加其他成员到你的结构说用的名字。

所以,如果你有两个人用的63个,但不同forenames的ID,他们是等于或不?

一切都取决于定义的“相同”要实现。

使用一个更好的例子结构,写一个诺迪applictaion执行各种方法,看看当你改变平等或同等教育的定义,如果他们是不是所有的步骤发生了什么,你最终得到的东西一样!(一== b)!=(A!= b),这可能是真实的,但如果你不覆盖任何人使用你的代码将不知道你的意图是什么,所有的方法。

基本上,编译器告诉你是好公民,让你的意图明确。



Answer 5:

大概是因为默认Equals()方法,预计不会成为一个真正的系统不够好(例如,在你的类应该比较ID字段)。



Answer 6:

阅读MSDN页面。

CS0660

CS0661

编译器基本上是说:“既然你说知道怎么比较你的目标,你应该把它比这样所有的时间。”



Answer 7:

如果重写EqualsGetHashCode你甚至不会需要覆盖运营商,这是一个更简洁的方法。 编辑:它应该工作,因为这是一个结构。



Answer 8:

public struct Coord
{
    public int x;
    public int y;

    public Coord(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

    public static bool operator ==(Coord c1, Coord c2)
    {
        return c1.x == c2.x && c1.y == c2.y;
    }

    public static bool operator !=(Coord c1, Coord c2)
    {
        return !(c1 == c2);
    }

    public bool Equals(Coord other)
    {
        return x == other.x && y == other.y;
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        return obj is Coord && Equals((Coord) obj);
    }

    public override int GetHashCode()
    {
        return 0;
    }
}

下面是一个例子。 我们希望,这是有帮助的。



文章来源: What's wrong with defining operator == but not defining Equals() or GetHashCode()?