平等但不可互换

时间:2013-08-06 03:29:23

标签: c# equality

我有两个类似的对象:

class Container {
    public HashSet<Item> Items { get; }
}

class Item {
    public Container Parent { get; set; }
    public string Value1 { get; set; }
    public int Value2 { get; set; }
}

每个Item实例必须属于Container实例,并且两者之间存在一对多关系,并且两端始终保持同步。

我现在面临着实施一种方法,该方法会比较Item的两个实例,以查看其Value1Value2值是否匹配。该方法将考虑Parent值,因为我比较的每对实例在此值上肯定不同,所以这样做会使我实现的方法无用,因为它会有与false方法相同的结果(object.ReferenceEquals)。

我的问题如下。我应该将此方法实现为对象的public override bool Equals( object obj )方法(以及GetHashCode)吗?或者它忽略了它的Parent属性的事实使我无法这样做?为什么或者为什么不?我的另一个想法是将其实现为public bool EqualsIgnoreParent( Item other ),它不会覆盖任何东西;然后我可以从自定义比较器中调用它。

5 个答案:

答案 0 :(得分:1)

感谢mikez's comment和Eric Lippert的blog post,我发现我不应该覆盖Item的{​​{1}}或Equals方法,因为{{ 1}}的实例是可变的并添加到GetHashCode

根据建议here,我决定将两个平等概念分开。

  1. 身份。我做了覆盖Item的{​​{1}}和HashSet方法。我将这些方法保留在Item中。这就是Equals将使用的内容。
  2. 等效。我创建了一个名为GetHashCode的公共单例类,它嵌套在object中并实现HashSet。这就是我在我的问题中描述的比较逻辑。

答案 1 :(得分:0)

我猜你想要实现IEquatable。所以我建议你只用Euqals(Item other)重载Euqals(对象),同时通过调用Equals(Item other)来覆盖Equals(对象)。

当然,让GetHashCode返回-1总是强制通过Equals进行相等比较。这里有一个解释为什么需要覆盖GetHashCode方法 - Why is it important to override GetHashCode when Equals method is overridden?

答案 2 :(得分:0)

是的,您可以使用Equals和GetHashCode,实现此功能,只要Value1和Value2不会更改或您的哈希值与任何更改无关。 (否则使用您的HashCode的集合将不起作用)

此外,您可以将Item类减少为基本成员

class Item {
    public string Value1 { get; set; }
    public int Value2 { get; set; }
}

并在另一个字典中维护关系:(如果正确实现GetHashCode,这将是有效的)

Dictionary<Item, Container> ContainersOfItems;

答案 3 :(得分:0)

我建议拆分Item可能更有意义,所以它看起来像:

class Container<TContent> {
    public HashSet<Item<TContent>> Items { get; }
}

class Item<TContent> {
    public Container Parent;
    public TContent Content;
}

如果您这样做,那么您可以定义一种类型来保存您的内容,该类型具有适合该类型的Equals方法,并使用HashSet初始化您的IEqualityComparer<Item<TConcent>>每个Item<TContent>的{​​{1}}字段。

答案 4 :(得分:-1)

不要这样做,除非你100%确定父成员永远不会有任何不同。可能有许多你没想到的用例,(如果你需要将2个容器中的项目放在一个字典中怎么办?)所以我建议坚持设计。如果按照定义,平等只由其他成员决定,那就去吧。否则,不是。
您以后总是可以编写特定于案例的相等逻辑。请注意,DictionaryListHashSet和其他收集可让您定义自定义IEqualityComparer
还有另一种选择,但要非常小心。覆盖两种方法,但使GetHashCodeEquals更宽容,这意味着,使不等对象具有相同的哈希码,而不是相反。让GetHashCode忽略父成员,但不忽略Equals。它不会伤害任何东西,然后如果你想忽略词典中的父成员,写一个IEqualityComparer,用GetHashCode的方式比较它们。