2

我正在尝试将 (name: string, value: long) 对存储在一个集合中。

public class NameValuePair
{
  public string name;
  public long value;
}

public NameValuePairComparer comparer = new NameValuePairComparer();
public HashSet<NameValuePair> nameValueSet = new HashSet<NameValuePair>(comparer);

如果两个对具有相同的名称或相同的值,则它们是相等的 - 这在 NameValuePairComparer 中实现,覆盖 EqualityComparer 的 Equals 方法:

public class NameValuePairComparer : EqualityComparer<NameValuePair>
{
   public override bool Equals(NameValuePair x, NameValuePair y)
   {
      return (x.value == y.value) || (x.name == y.name);
   }

问题是:GetHashCode(NameValuePair obj) 应该为 Equals 返回 true 的两个对象返回相同的值,因此对于给定的 NameValuePair,GetHashCode() 应该返回 value.GetHashCode() 或 name.GetHashCode(),但要这样做我们必须知道两对中的哪个字段相等:

   public override int GetHashCode(NameValuePair obj)
   {
      /* ??? */
      /* // Using unknown reference to x
        if (obj.value == x.value) return obj.value.GetHashCode();
        else if (obj.name == x.name) return obj.name.GetHashCode();
        else return base.GetHashCode(obj);
      */
   }
}

但是我们不知道这一点,这意味着我不能使用 HashSet 来存储这些对,也不能使用 EqualityComparer。

问:C# (.net 3.5) 中是否有基于非散列的 set 实现?

问:使用自定义相等比较器存储唯一 NameValuePairs 的更好方法是什么?

4

1 回答 1

6

如果两个对具有相同的名称或相同的值,则它们是相等的

您根本无法IEqualityComparer<T>使用这些标准正确实施。从以下文档Equals

Equals 方法是自反的、对称的和传递的。也就是说,如果用于将对象与自身进行比较,则返回true;如果对 y 和 x 为真,则对两个对象 x 和 y 为真;如果对 x 和 y 为真并且对 y 和 z 也为真,则对两个对象 x 和 z 为真。

现在考虑对:

x = { "A", 10 },
y = { "A", 20 },
z = { "B", 20 }

您是说xandy必须相等,因为它们具有相同的名称,并且yandz必须相等,因为它们具有相同的值。这意味着(通过传递性)x并且z应该是相等的。

由于您无法IEqualityComparer<T>正确实施,因此您不应期望任何依赖于该正确性的东西都能正常工作。

我怀疑您会发现,如果您更详细地查看您的需求,它们要么真的需要两个集合(一个按名称,一个按值),要么就传递性而言它们没有意义。

例如,假设您有一个具有您建议的特征的集合,并且您添加了上面的三个元素。如果您按 { x, y, z } 的顺序添加它们,您最终会得到一个条目。如果您按 { z, x, y } 的顺序添加它们,您最终会得到两个。那是一种有用的集合吗?

于 2013-03-18T10:37:45.310 回答