实现Equals以使引用相等或基于密钥的相等?

时间:2018-06-09 19:21:36

标签: c#

我想覆盖我的EntityBase类的EqualsGetHashCode,以支持基于引用(默认情况下)或实体键(如果引用不匹配)检查相等性。 这是代码:

public abstract class EntityBase
{
    protected virtual object Keys { get { return this; } }
    public override bool Equals(object obj)
    {
        if (Keys == this) return base.Equals(obj);
        var entity = obj as EntityBase;
        if (entity == null) return false;
        var re = ReferenceEquals(entity, this);
        return re || Equals(entity.Keys, Keys);
    }
    public override int GetHashCode()
    {
        if (Keys == this) return base.GetHashCode();
        return base.GetHashCode() * 17 + (Keys?.GetHashCode() ?? 0);
    }
}

现在在派生类中,它可以是这样的:

public class Entity : EntityBase {
    protected override object Keys {
        get {
             return SomeKeyProperty;
        }
    }
}

所以我希望它能够正常运行,但我使用的BindingSource表明它不起作用,就像这样:

//the myEntity here is contained (as reference) in myBindingSource  
var index = myBindingSource.IndexOf(myEntity);

如果我没有覆盖Equals类的EntityBase,上面的代码会给出正确的结果,但是如果重写,结果将是错误的,看起来总是试图看起来对于基于Keys值的项目。我真的不明白这里的错误。

调试时,它甚至没有达到我在Equals方法中设置的断点。代码只是通过IndexOf调用,就像它是一个黑盒子一样。

你能否向我解释一下这里有什么问题,并给我一些关于可能修复的建议(或者甚至让我知道我想达到的目标是否可行)。

1 个答案:

答案 0 :(得分:0)

实际上我发布的代码就像它应该的那样运行。我希望引用相等应该具有更高的优先级,但实际上当在集合中找到一个项目(如IndexOf)时,首先发现的是(如果引用不匹配则将使用键)

它之所以无法正常工作的原因是因为这里比较的两个都有Keys等于0。因此,如果使用基于密钥的相等性,则应将该情况视为unequal。我需要添加另一个属性来确定哪个值被视为null或空Keys。以下是我预期的代码:

public abstract class EntityBase
{
    protected virtual object Keys { get { return this; } }
    protected virtual object EmptyKeys {get { return null;} }
    public override bool Equals(object obj)
    {
      if (Keys == this) return base.Equals(obj);
      var entity = obj as EntityBase;
      if (entity == null) return false;
      var re = ReferenceEquals(entity, this);
      return re || GetType() == entity.GetType() && Equals(entity.Keys, Keys) && !Equals(Keys, EmptyKeys);
    }
    public override int GetHashCode()
    {
      if (Keys == this) return base.GetHashCode();
      return base.GetHashCode() * 17 + (Keys?.GetHashCode() ?? 0);
    }
}

在派生类中,我们需要覆盖EmptyKeys以指示哪个值被视为空,请注意,对于数字键(如long,...),{{1}的值应该是EmptyKeys的确切类型,否则Keys将不起作用。

Equals

在调整之后,代码可以正常工作。