我正在尝试在一个集合中存储(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会有什么更好的方法?
答案 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 }
您说x
和y
必须相同,因为它们具有相同的名称,并且y
和z
必须相同,因为它们具有相同的值。这意味着(通过传递性)x
和z
应该相等。
由于您无法正确实施IEqualityComparer<T>
,因此您不应期望任何依赖于该正确性的内容。
我怀疑你会发现,如果你更详细地查看你的要求,他们要么真的要求两个集合(一个按名称,一个按值)或根据传递性,它们没有意义。
例如,假设您有一个具有您建议的特征的集合,并添加上面的三个元素。如果按照{x,y,z}的顺序添加它们,您最终会得到一个条目。如果按照{z,x,y}的顺序添加它们,最终会得到两个。这是一个有用的设置怎么样?