基于非哈希的集合集合,用于使用自定义相等比较器存储唯一对象 - C#

时间:2013-03-18 10:34:51

标签: c# collections set unique iequalitycomparer

我正在尝试在一个集合中存储(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会有什么更好的方法?

1 个答案:

答案 0 :(得分:6)

  

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

您根本无法使用这些条件正确实施IEqualityComparer<T>。来自Equals的文档:

  

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

现在考虑对:

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

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

由于您无法正确实施IEqualityComparer<T>,因此您不应期望任何依赖于该正确性的内容。

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

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