我正在研究如何为类构建最好的HashCode,我看到了一些算法.我看到了这一个:Hash Code实现,似乎是.NET类HashCode方法类似(通过反映代码看).
所以问题是,为什么不创建上面的静态类以便自动构建HashCode,只需传递我们认为是"键"的字段.
// Old version, see edit
public static class HashCodeBuilder
{
public static int Hash(params object[] keys)
{
if (object.ReferenceEquals(keys, null))
{
return 0;
}
int num = 42;
checked
{
for (int i = 0, length = keys.Length; i < length; i++)
{
num += 37;
if (object.ReferenceEquals(keys[i], null))
{ }
else if (keys[i].GetType().IsArray)
{
foreach (var item in (IEnumerable)keys[i])
{
num += Hash(item);
}
}
else
{
num += keys[i].GetHashCode();
}
}
}
return num;
}
}
Run Code Online (Sandbox Code Playgroud)
并像这样使用它:
// Old version, see edit
public sealed class A : IEquatable<A>
{
public A()
{ }
public string Key1 { get; set; }
public string Key2 { get; set; }
public string Value { get; set; }
public override bool Equals(object obj)
{
return this.Equals(obj as A);
}
public bool Equals(A other)
{
if(object.ReferenceEquals(other, null))
? false
: Key1 == other.Key1 && Key2 == other.Key2;
}
public override int GetHashCode()
{
return HashCodeBuilder.Hash(Key1, Key2);
}
}
Run Code Online (Sandbox Code Playgroud)
会更简单,总是自己的方法,不是吗?我错过了什么?
根据所有评论,我得到以下代码:
public static class HashCodeBuilder
{
public static int Hash(params object[] args)
{
if (args == null)
{
return 0;
}
int num = 42;
unchecked
{
foreach(var item in args)
{
if (ReferenceEquals(item, null))
{ }
else if (item.GetType().IsArray)
{
foreach (var subItem in (IEnumerable)item)
{
num = num * 37 + Hash(subItem);
}
}
else
{
num = num * 37 + item.GetHashCode();
}
}
}
return num;
}
}
public sealed class A : IEquatable<A>
{
public A()
{ }
public string Key1 { get; set; }
public string Key2 { get; set; }
public string Value { get; set; }
public override bool Equals(object obj)
{
return this.Equals(obj as A);
}
public bool Equals(A other)
{
if(ReferenceEquals(other, null))
{
return false;
}
else if(ReferenceEquals(this, other))
{
return true;
}
return Key1 == other.Key1
&& Key2 == other.Key2;
}
public override int GetHashCode()
{
return HashCodeBuilder.Hash(Key1, Key2);
}
}
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 12
你的Equals方法被破坏 - 它假设具有相同哈希码的两个对象必然相等.事实并非如此.
你的哈希码方法看起来很好看,但实际上可以做一些工作 - 见下文.它意味着在任何时候调用任何值类型值并创建数组,但除此之外它没关系(正如SLaks指出的那样,集合处理存在一些问题).您可能需要考虑编写一些通用的重载,以避免常见情况下的性能损失(可能是1,2,3或4个参数).您可能还想使用foreach循环而不是普通for循环,只是为了惯用.
你可以做同样的排序为平等的事情,但它是稍硬和混乱.
编辑:对于哈希代码本身,您只需要添加值.我怀疑你是试图做这种事情:
int hash = 17;
hash = hash * 31 + firstValue.GetHashCode();
hash = hash * 31 + secondValue.GetHashCode();
hash = hash * 31 + thirdValue.GetHashCode();
return hash;
Run Code Online (Sandbox Code Playgroud)
但是,乘以 31的哈希,它不会增加 31.目前您的散列码总是返回相同的值相同,无论他们是否是在相同的顺序,这是不理想的.
编辑:似乎对使用的哈希码有一些混淆.我建议任何不确定的人阅读文档Object.GetHashCode,然后阅读Eric Lippert 关于哈希和平等的博客文章.
| 归档时间: |
|
| 查看次数: |
8969 次 |
| 最近记录: |