简短问题
如何为GetHashCode
实施Array
。
详情
我有一个覆盖Equals
的对象,检查:
this.array[n] == otherObject.array[n]
适用于n
中的所有array
。
当然,我应该实施补充GetHashCode
。
我想知道是否有.NET方法可以做到这一点,或者我是否应该实现自己的方式,比如
hash = hash ^ array[n]
澄清
我的对象包含一个数组,我对GetHashCode感兴趣的数组元素。我的数组等价代码仅作为示例 - 就像我的问题所说,但也许我不清楚,我对GetHashCode
感兴趣(不是Equals
)。我说我自然应该实现补充GetHashCode
,因为一旦Equals
被覆盖(Dictionary
等正常运行),实现这一点就需要.NET。感谢。
答案 0 :(得分:7)
要使用数组元素计算哈希代码,可以将数组转换为IStructuralEquatable,然后调用GetHashCode(IEqualityComparer)方法,为数组中的元素类型传递比较器。 / p>
(强制转换是必要的,因为Array类显式实现了该方法。)
例如,如果您的对象具有int
数组,那么您可以像这样实现GetHashCode:
public override int GetHashCode()
{
return ((IStructuralEquatable)this.array).GetHashCode(EqualityComparer<int>.Default);
}
如果你有点好奇,这里是Array类如何实现GetHashCode方法(来自Reference Source):
internal static int CombineHashCodes(int h1, int h2) {
return (((h1 << 5) + h1) ^ h2);
}
int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) {
if (comparer == null)
throw new ArgumentNullException("comparer");
Contract.EndContractBlock();
int ret = 0;
for (int i = (this.Length >= 8 ? this.Length - 8 : 0); i < this.Length; i++) {
ret = CombineHashCodes(ret, comparer.GetHashCode(GetValue(i)));
}
return ret;
}
如您所见,当前实现仅使用数组的最后八个元素。
答案 1 :(得分:4)
我不同意您应该自然地在阵列上实现GetHashCode
您必须在每次更改时更新它
或者在飞行中计算
我会在飞行中直接比较
SequenceEquals将使用默认的相等比较器,因此您还应该实现
public bool Equals
>>
中的对象 Enumerable.SequenceEqual
有一个例子
public static void SequenceEqualEx1()
{
Pet pet1 = new Pet { Name = "Turbo", Age = 2 };
Pet pet2 = new Pet { Name = "Peanut", Age = 8 };
// Create two lists of pets.
List<Pet> pets1 = new List<Pet> { pet1, pet2 };
List<Pet> pets2 = new List<Pet> { pet1, pet2 };
bool equal = pets1.SequenceEqual(pets2);
Console.WriteLine(
"The lists {0} equal.",
equal ? "are" : "are not");
}
答案 2 :(得分:1)
这取决于您想要...
Michael上面回答的一个选择是基于数组元素具有哈希码。这将符合您的Equals值语义。但是,由于“作为准则,对象的散列在对象的整个生命周期中必须相同”,因此,您必须确保数组在获得其散列码后不发生变化。拥有一个永远不变的需求的不变容器,这对我来说很容易出错。
您的另一个(IMO更好的选择)是切换到不可变容器(即ImmutableArray),然后基于值的哈希码才有意义。您可以如上所述使用IStructuralEquatable
,也可以更普遍地使用:
public override GetHashCode() {
int ret = 0, index = 0, startIndex = collection.Count >= 8 ? collection.Count - 8 : 0;
foreach (var v in Value) if (index >= startIndex) ret = HashCode.Combine(ret, v.GetHashCode());
return ret;
}
同样适用于其他不可变集合。
答案 3 :(得分:0)
使用当前框架,可以考虑使用
int value=0;
for (var i = 0;i< this.array.Length; i++)
{
value=HashCode.Combine(this.array[i],value);
}