首页 > 解决方案 > 实现 Equals 以使引用相等或基于键的相等?

问题描述

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

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一个黑盒子一样通过调用运行。

您能否向我解释这里出了什么问题,并就可能的解决方法给我一些建议(或者甚至让我知道我想要实现的目标是否可行)。

标签: c#

解决方案


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

它没有按我预期工作的原因是因为这里比较的 2 个都Keys等于0. 因此,如果使用基于键的相等性,则应将这种情况视为unequal. 我需要添加另一个属性来确定哪个值被视为 null 或 empty 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,...),值EmptyKeys应该是与 的确切类型Keys,否则Equals将不起作用。

public class Entity : EntityBase {
   protected override object Keys {
      get {
         return SomeKeyProperty;//suppose this is a long property
      }
   }
   protected override object EmptyKeys {
      get {
         return 0L;//here 0 value should also be a long value.
      }
   }
}

调整后,代码按预期工作。


推荐阅读