【问题标题】:Writing A Good C# Equals Method编写一个好的 C# Equals 方法
【发布时间】:2010-03-24 17:31:14
【问题描述】:

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

我没有这本书,我不记得它是否是实用的建议 - 那么你如何编写一个可靠、健壮的 equals 方法实现?

【问题讨论】:

    标签: c#


    【解决方案1】:

    可能是一个现成的建议,但:首先考虑不要覆盖Equals。正如您所提到的,基本上平等的性质不适用于子类化。然而,.NET API 中使用相等的几乎所有地方(例如字典、哈希集)都允许传入 IEqualityComparer<T>。使不同的对象负责相等使生活更加灵活:您可以使用不同的对象来确定哪个使用标准。

    实现IEqualityComparer<T> 要简单得多——您仍然需要检查是否为空,但您不必担心类型是否合适,或者Equals 是否会被进一步覆盖。

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

    【讨论】:

      【解决方案2】:

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

      Implementing the Equals Method

      【讨论】:

        【解决方案3】:

        一个好的equals方法的属性:

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

        【讨论】:

          【解决方案4】:

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

          public abstract class ValueObject<T> : IEquatable<T>
              where T : ValueObject<T>
          {
              protected abstract IEnumerable<object> 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<Person>
          {
              public int Age { get; set; }
              public string Name { get; set; }
          
              protected override IEnumerable<object> Reflect()
              {
                  return new object[] { Age, Name };
              }
          }
          

          Reflect 覆盖中,您返回需要有助于相等的值序列。

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

          【讨论】:

            【解决方案5】:

            【讨论】:

              【解决方案6】:

              我通常会这样做:

              public struct EmailAddress : IEquatable<EmailAddress>
              {
                  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;
                  }
              }
              

              【讨论】:

                【解决方案7】:

                “好的”equals 方法是一种比较类的独特部分而忽略不利于独特性的部分的方法。因此,如果您有一个具有唯一 id 的类,您可以使用它来建立相等性,而忽略任何其他属性。不过,您通常还需要一些时间戳值。

                【讨论】:

                  【解决方案8】:

                  公共类人 { 公共字符串名称 { 获取;放; }

                      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;
                      }
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2023-03-08
                    • 1970-01-01
                    • 2020-03-14
                    • 1970-01-01
                    相关资源
                    最近更新 更多