c# - 用不同的属性覆盖 GetHashCode

标签 c# overriding

我有这个对象:

public class Foo  {
    public string MyOwnId { get; set; }
    public Guid FooGuid { get; } = Guid.NewGuid();
}

我希望 Equals() 只关心那些有 MyOwnId 的,否则它们永远不相等。当 Foo 有一个 MyOwnId 时,我尝试使用它,否则我想使用 FooGuid

因为 FooGuid 可能永远不会相同,所以我做了这样的事情:

public bool Equals(Foo foo) {
        if (foo== null) return false;
        return MyOwnId.Equals(foo.MyOwnId);
    }

    public override bool Equals(object obj) {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != this.GetType()) return false;
        return Equals((Foo)obj);
    }

    public override int GetHashCode() {
        int hash = 13;
        hash = (hash*7) + (!string.IsNullOrEmpty(MyOwnId) ? MyOwnId.GetHashCode() : FooGuid.GetHashCode());
        return hash;
    }

这是做我想做的事情的正确方法吗?或者我是否还需要更改我的 Equals 方法,使其看起来与我的 GetHashCode 相同?例如:

public bool Equals(Foo foo) {
        if (foo == null) return false;
        if (string.IsNullOrEmpty(MyOwnId) || string.IsNullOrEmpty(foo.MyOwnId)) return false;
        return MyOwnId.Equals(foo.MyOwnId);
    }

最佳答案

好吧,让我们看看。您对 EqualsGetHashCode 的实现是错误的

EqualsGetHashCode 绝不能抛出异常;反例是

  Foo A = new Foo();
  Foo B = new Foo() {
    MyOwnId = "bla-bla-bla",
  };

  // Throws an exception
  if (A.Equals(B)) {}

如果两个实例通过Equals 相等,则这些实例必须具有相同的哈希码;反例是

  Foo A = new Foo() {
    MyOwnId = "",
  };

  Foo B = new Foo() {
    MyOwnId = "",
  };

  if (A.Equals(B)) {
    // Hashcodes must be equal and they are not
    Console.Write(String.Format("{0} != {1}", A.GetHashCode(), B.GetHashCode()));
  }

可能的(最简单的)实现

// since you've declared Equals(Foo other) let others know via interface implementation
public class Foo: IEquatable<Foo> { 
  public string MyOwnId { get; set; }
  public Guid FooGuid { get; } = Guid.NewGuid();

  public bool Equals(Foo other) {
    if (Object.ReferenceEquals(this, other))
      return true;
    else if (Object.ReferenceEquals(null, other))
      return false;
    else
      return String.Equals(MyOwnId, other.MyOwnId);
  }

  public override bool Equals(object obj) {
    return Equals(obj as Foo); // do not repeat youself: you've got Equals already
  }

  public override int GetHashCode() {
    // String.GetHashCode is good enough, do not re-invent a wheel
    return null == MyOwnId ? 0 : MyOwnId.GetHashCode(); 
  }
}

关于c# - 用不同的属性覆盖 GetHashCode,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35063616/

相关文章:

c# - 我应该使用扩展方法来帮助从 DataRow/Table 创建模型对象吗?

c# - 如何以编程方式在 IIS 中托管 WCF 服务?

java - java中的非重写方法?

Objective-C 检测类是否覆盖了继承的方法

php - 如何在 wordpress 中的 fonts.php 之后加载 style.css?

c# - Silverlight 中的随机动画

c# - 用时区和夏令时确定一天的开始

java - 添加参数后覆盖具有泛型返回类型的方法失败

java - 如何在派生类中覆盖 `toString` 并使用基类中的私有(private)实例变量?

c# - 如何将 xaml 中的数据触发器绑定(bind)到代码定义的依赖属性?