C# 实现Equals以使引用相等或基于键的相等?
我希望重写EntityBase类的C# 实现Equals以使引用相等或基于键的相等?,c#,C#,我希望重写EntityBase类的Equals和GetHashCode,以支持基于引用(默认情况下)或通过实体键(如果引用不匹配)检查相等性。 代码如下: public abstract class EntityBase { protected virtual object Keys { get { return this; } } public override bool Equals(object obj) { if (Keys == this) re
Equals
和GetHashCode
,以支持基于引用(默认情况下)或通过实体键(如果引用不匹配)检查相等性。
代码如下:
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;
}
}
}
//the myEntity here is contained (as reference) in myBindingSource
var index = myBindingSource.IndexOf(myEntity);
所以我希望它能工作,但我使用的BindingSource
表明它不工作,如下所示:
public class Entity : EntityBase {
protected override object Keys {
get {
return SomeKeyProperty;
}
}
}
//the myEntity here is contained (as reference) in myBindingSource
var index = myBindingSource.IndexOf(myEntity);
如果我没有为我的EntityBase
类重写Equals
,上面的代码会给出正确的结果,但是如果使用该重写,结果将是错误的,看起来它总是试图基于键
值来查找项。我真的不明白这里出了什么问题
调试时,它甚至没有达到我在Equals
方法中设置的断点。代码只是像一个黑匣子一样通过IndexOf
调用运行
你能给我解释一下这里出了什么问题,并给我一些关于可能的修复方法的建议(或者甚至让我知道我想要实现的是不是可能的)。事实上,我发布的代码运行与它应该运行的一样。我希望引用相等应该具有更高的优先级,但实际上,在集合中查找项目(如
IndexOf
)时,首先出现的将是找到的项目(如果引用不匹配,则将使用键)
它没有像我预期的那样工作的原因是,这里比较的两个都有
键
等于0
。因此,如果使用基于键的相等,则应将这种情况视为不相等。我需要添加另一个属性来确定哪个值被视为null或空键
。以下是我所期望的代码:
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
的值应与键的类型完全相同,否则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.
}
}
}
调整后,代码正常工作。参考等式始终使用=
。基于键的相等可以简单地使用比较来实现。@Oighea你说的是直接比较对象,但这里我想把逻辑放在Equals
override中,这样一些集合会使用它,例如find indexI,我不认为这是推荐的。按照惯例,引用相等(它比键相等更强大)总是使用=
,当它工作时,Order#1==Custmer#1
不会返回true吗?当您必须添加越来越多的检查时,是时候重新考虑整个问题了。身份和平等是非常基本的概念,“这种情况应被视为不平等”,这表明整个想法是非常可疑的。你真的对此有一个频繁的用例吗?@HenkHolterman事实上它不是很频繁,我只是有一个对象列表,包括新添加的对象(它们的所有键都是空的/空的/零的)。新添加的实体可以等同于其他东西吗?我还没有看到超出引用质量的参数。@HenkHolterman我认为在这种情况下,相等性应该取决于它们的键
,引用在这里几乎不重要。@HenkHolterman基于键的相等性的另一个例子是在使用包装类时。该类只是围绕一个实体(并通过附加道具公开更多的信息)。参考平等仍然适用于他们,而基于关键的平等应该是重要的实施。