简体   繁体   English

实现等于使引用相等还是基于键的相等?

[英]Implement Equals to make either reference equality or key-based equality?

I would like to override the Equals and GetHashCode of my EntityBase class to support checking equality based on reference (as by default) or by the entity key (in case the references not matching). 我想重写EntityBase类的EqualsGetHashCode以支持根据引用(默认情况下)或实体键(如果引用不匹配)检查是否相等。 Here is the code: 这是代码:

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

Now in the derived class it can be like this: 现在在派生类中可以是这样的:

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

So I expect that it should work, but the BindingSource I'm using showed that it does not work, like this: 因此,我希望它应该可以工作,但是我正在使用的BindingSource表明它不起作用,如下所示:

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

The code above gives the correct result if I don't override Equals for my EntityBase class, but with that overriding, the result will be wrong, looks like it always tries to look for the item based on the Keys value. 如果我不为EntityBase类覆盖Equals ,则上面的代码将给出正确的结果,但是由于该覆盖,结果将是错误的,看起来它总是尝试根据Keys值来查找项。 I don't really understand what's wrong here. 我真的不明白这是怎么回事。

When debugging it does not even hit the breakpoint I set in the Equals method. 调试时,它甚至都没有达到我在Equals方法中设置的断点。 The code just runs through the IndexOf call like as it's a black box. 该代码就像一个黑盒子一样,通过IndexOf调用运行。

Could you explain to me what's wrong here and give me some suggestion about a possible fix (or even let me know if what I want to achieve is possible). 您能否向我解释这里出了什么问题,并给我一些有关可能的修复的建议(甚至让我知道我想要实现的目标是否可能)。

Actually the code I posted runs just like what it should. 实际上,我发布的代码可以正常运行。 I want that the reference equality should have higher priority, but really when finding an item (like IndexOf ) in a collection, what comes first will be the one found (if the references does not match then keys will be used). 我希望引用相等性具有更高的优先级,但实际上在集合中找到一个项目(如IndexOf )时,首先出现的将是找到的对象(如果引用不匹配,则将使用键)。

The reason it did not work as I expect because the 2 ones compared here both have Keys equal to 0 . 它不能按我预期的那样工作的原因是,这里比较的2个都具有等于0 Keys So if key-based equality is used, that case should be considered as unequal . 因此,如果使用基于密钥的相等性,则该情况应视为unequal I need to add another property to determine which value is considered as null or empty Keys . 我需要添加另一个属性来确定哪个值被视为null或空Keys Here is the code working as I expected: 这是我期望的代码:

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

In the derived class, we need to override the EmptyKeys to indicate which value is considered as empty, NOTE that for numeric key (like long , ...) the value for EmptyKeys should be of the exact type with Keys , otherwise the Equals won't work. 在派生类中,我们需要重写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.
      }
   }
}

After that adjusting, the code works expectedly. 调整之后,代码将正常工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM