编写一个好的C#Equals方法

有没有人有一个模板来编写一个像样的equals方法 – 我记得在Effective Java中,在处理子类时遇到了处理equals的问题。

我没有这本书,我不记得这是否是实用的建议 – 所以你如何写一个坚实的强大的equals方法实现?

可能是一个离谱的建议,但是:首先考虑不要压倒Equals 。 正如您所提到的,基本上,平等的性质不适用于子类化。 但是,.NET API中使用相等的几乎所有地方(例如字典,散列集)都允许传入IEqualityComparer 。使不同的对象负责相等性使生活变得更加灵活:您可以使用不同的对象来确定使用哪个标准。

实现IEqualityComparer要简单得多 – 您仍然需要检查是否为null,但是您不必担心类型是否合适,或者是否将进一步覆盖Equals

使正常Equals工作更顺利的另一种方法是在大多数情况下完全避免inheritance – 我不记得上次在我的代码中真正有意义覆盖Equals 允许派生类。 sealed FTW 🙂

您可能已经这样做了,但是您查看了有关实现Equals()的MSDN文章吗?

实现Equals方法

如果您厌倦了为此编写大量样板文件,可以尝试使用为您实现它的基类。

 public abstract class ValueObject : IEquatable where T : ValueObject { protected abstract IEnumerable Reflect(); public override bool Equals(Object obj) { if (ReferenceEquals(null, obj)) return false; if (obj.GetType() != GetType()) return false; return Equals(obj as T); } public bool Equals(T other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return Reflect().SequenceEqual(other.Reflect()); } public override int GetHashCode() { return Reflect().Aggregate(36, (hashCode, value) => value == null ? hashCode : hashCode ^ value.GetHashCode()); } public override string ToString() { return "{ " + Reflect().Aggregate((l, r) => l + ", " + r) + " }"; } } 

现在要制作一个类似于价值的课程,你只需说:

 public class Person : ValueObject { public int Age { get; set; } public string Name { get; set; } protected override IEnumerable Reflect() { return new object[] { Age, Name }; } } 

Reflect覆盖中,您将返回需要促成相等性的一系列值。

不幸的是,这种方法无法帮助声明operator == ,因为必须在派生类型上明确声明。

良好等于方法的属性:

  • 对称性 :对于两个引用,a和b,a.equals(b)当且仅当b.equals(a)
  • 自反性 :对于所有非空引用,a.equals(a)
  • 及物性 :如果a.equals(b)和b.equals(c),则a.equals(c)

在MSDN上查看重载等于()和运算符==的指南 。

我通常做这样的事情:

 public struct EmailAddress : IEquatable { public override bool Equals(object obj) { return obj != null && obj.GetType() == typeof(EmailAddress) && Equals((EmailAddress)obj); } public bool Equals(EmailAddress other) { return this.LocalPart == other.LocalPart && this.Domain == other.Domain; } } 

“好”等于方法是一种方法,它比较类的唯一部分,同时省略不贡献唯一性的部分。 因此,如果您的类具有唯一的id,则可以使用它来建立相等性,而忽略任何其他属性。 但是,您通常也需要一些时间戳值。

public class Person {public string Name {get; 组; }

  public int Age { get; set; } public override bool Equals(object obj) { var objAsPerson = obj as Person; if (obj == null) { return false; } if (this.Name != objAsPerson.Name) { return false; } if (this.Age != objAsPerson.Age) { return false; } return true; } }