2010-12-12 130 views
10

你在编写对你创建的structsclasses进行相等性检查的方法是什么?C#平等检查

1)是否 “完全” 平等检查需要大量的样板代码(如override Equalsoverride GetHashCode,通用Equalsoperator==operator!=)?

2)您是否明确指定您的类将模拟IEquatable<T>接口?

3)我是否理解正确的话,那还有自动应用Equals覆盖没有实际的办法,当调用类似a == b,我总是要同时实现Equalsoperator==成员?

回答

20

你说得对,这是一个很大的锅炉板代码,你需要单独实现的一切。

我会推荐:

  • 如果你要实现价值平等可言,覆盖GetHashCodeEquals(object) - 用于创建==超载和实施IEquatable<T>没有做,可能会导致非常意外的行为
  • 我会始终贯彻IEquatable<T>如果你覆盖Equals(object)GetHashCode
  • 我只有正确重载==操作符更很少
  • 实现平等启封类是棘手的,而且还可以产生令人惊讶的/不希望的结果。如果您需要层次结构中的类型相等,请执行IEqualityComparer<T>表示您感兴趣的比较。
  • 可变类型的平等通常是一个坏主意,因为两个对象可以相等,然后不等。如果一个对象在用作哈希表中的关键字后发生了变化(以影响等式的方式),您将无法再次找到它。
  • 一些锅炉板的结构略有不同...但像马克,我很少写自己的结构。

这里是一个示例实现:

using System; 

public sealed class Foo : IEquatable<Foo> 
{ 
    private readonly string name; 
    public string Name { get { return name; } } 

    private readonly int value; 
    public int Value { get { return value; } } 

    public Foo(string name, int value) 
    { 
     this.name = name; 
     this.value = value; 
    } 

    public override bool Equals(object other) 
    { 
     return Equals(other as Foo); 
    } 

    public override int GetHashCode() 
    { 
     int hash = 17; 
     hash = hash * 31 + (name == null ? 0 : name.GetHashCode()); 
     hash = hash * 31 + value; 
     return hash; 
    } 

    public bool Equals(Foo other) 
    { 
     if ((object) other == null) 
     { 
      return false; 
     } 
     return name == other.name && value == other.value; 
    } 

    public static bool operator ==(Foo left, Foo right) 
    { 
     return object.Equals(left, right); 
    } 

    public static bool operator !=(Foo left, Foo right) 
    { 
     return !(left == right); 
    } 
} 

是的,这是一个很大的样板赫克,这很少的实现:(

==实施是稍微之间变化效率比它可能低,因为它会通过呼吁Equals(object)哪些需要做动态类型检查...但替代是更多的锅炉板,如下所示:

public static bool operator ==(Foo left, Foo right) 
{ 
    if ((object) left == (object) right) 
    { 
     return true; 
    } 

    // "right" being null is covered in left.Equals(right) 
    if ((object) left == null) 
    { 
     return false; 
    } 
    return left.Equals(right); 
} 
+1

^^你的每个职位是一个C#学习章节.. :) – Dienekes 2010-12-14 10:08:15

+0

对于第二个代码块的2个小建议:1)你不应该把==(对象)从== =='移动到通用'Equals'吗?因此,即使对于通用的“Equals”方法,速度(当然这取决于,但假设最坏的情况)会检查引用相等性吗? 2)你不需要在'=='中进行第二次空的检查'(对象)right == null',因为你基本上是在泛型'Equals'中做的。看到我的帖子.. – nawfal 2012-12-16 20:53:24

+0

@nawfal:我认为在通用的'Equals'情况下做这件事并没有多大意义 - 无论如何,在* *为true的情况下它会很快,对于它的情况*不是真的,它增加了一个额外的检查没有任何好处。至于零部分 - 这将需要再次检查动态类型。是的,你可以为两者争辩 - 但我很满意我两年前写的东西...... – 2012-12-16 20:58:04

1

你只需要实现== == b的运算符==。
因为我喜欢我的数据在字典有时我重写GetHashCode。
接下来我实现了Equals(作为未提及的标准......这是因为在使用泛型时没有对平等的限制)并指定实现IEquatable。由于我要这样做,所以我不妨将我的==和!=实现指向Equals。 :)

6

我很少做任何特别的课程;对于大多数常规对象而言,引用平等很好。我很少写一个struct;但由于结构代表的值通常提供平等等是合适的。这通常涉及一切;等于,==,!=和IEquatable<T>(因为这使用EqualityComparer<T>.Default避免场景拳击。

样板通常不是问题太多,但IIRC工具,如ReSharper的帮助在这里。

是的,这是明智的保持Equals和==同步,而这需要明确地完成。