来自同一程序集的System.Type类型对象的哈希码是否保证唯一?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了来自同一程序集的System.Type类型对象的哈希码是否保证唯一?相关的知识,希望对你有一定的参考价值。

澄清编辑:字典中的键是System.Type的实际实例。更具体地说,每个值都以其类型作为键存储。

在我的程序的特定部分中,根据Visual Studio 2017性能分析器,Dictionary<System.Type, SomeThing>的使用占用了大量的CPU时间。

将字典类型更改为Dictionary<int, SomeThing>而不是直接传递类型对象我通过type.GetHashCode()似乎要快20%-25%。

如果两种类型具有相同的哈希码,则上述优化将导致一个讨厌的错误,但似乎我认为类型可以具有唯一的哈希码,至少在涉及来自相同汇编的类型时 - 所有类型都使用这本词典是。

可能相关的信息 - 根据this answer,装配中可能类型的数量远小于System.Int32所代表的值的数量。

答案

不。文件on object.GetHashCode()不作任何保证,并声明:

哈希码旨在用于在基于哈希表的集合中进行有效插入和查找。哈希码不是永久值。为此原因:

...

  • 不要使用哈希代码作为从密钥集合中检索对象的密钥。

因为相同的哈希码是必要的,但不足以使两个对象相等。

如果你想知道Type.GetHashCode()是否遵循更严格的定义,its documentation没有提到这样的改变,所以它仍然不能保证唯一性。 reference source也没有表现出任何提出这种保证的企图。

另一答案

对于不同的值,哈希代码永远不会保证是唯一的,因此您不应该像使用它一样使用它。但是,相同的值应该生成相同的哈希码。

这也在MSDN中说明:

两个相等的对象返回相等的哈希码。但是,相反的情况并非如此:相等的哈希码并不意味着对象相等,因为不同(不相等)的对象可以具有相同的哈希码。

并进一步:

不要使用哈希代码作为从密钥集合中检索对象的密钥。

因此,我也不会依赖于不同类型的GetHashCode是唯一的,但至少,你可以验证它:

Dictionary<int, string> s = new Dictionary<int, string>();

var types = typeof(int).Assembly.GetTypes();

Console.WriteLine($"Inspecting {types.Length} types...");

foreach (var t in typeof(-put a type from that assembly here-).Assembly.GetTypes())
{
    if (s.ContainsKey(t.GetHashCode()))
    {
        Console.WriteLine($"{t.Name} has the same hashcode as {s[t.GetHashCode()]}");
    }
    else
    {
        s.Add(t.GetHashCode(), t.Name);
    }
}

Console.WriteLine("done!");

但即使上面的测试得出的结论是没有冲突,我也不会这样做,因为GetHashCode的实现可能会随着时间而改变,这意味着将来可能会发生冲突。

另一答案

哈希码不是唯一的。相反,它用于基于散列的集合,例如Dictionary,以限制可能的歧义的数量。 hashc-ode只是一个索引,因此不必搜索整个集合中的匹配项,而只需要考虑共享一个共同值的几个项 - 哈希码。

实际上你甚至可以有一个哈希实现,它总是为每个项返回相同的数字。然而,这将导致O(n)在您的字典中查找密钥,因为必须比较每个密钥。

无论如何,你不应该努力进行微观优化,以获得一些纳秒来换取可维护性和可理解性。您应该使用一些数据结构来完成工作并且易于理解。

以上是关于来自同一程序集的System.Type类型对象的哈希码是否保证唯一?的主要内容,如果未能解决你的问题,请参考以下文章

使用来自另一个 MEF 程序集的类而不引用它

.NET Framework反射总结

来自程序集的类型是使用旧版本的 blend sdk 构建的,并且在 Windows Presentation Foundation 4 项目中不受支持

s-s-rS 2008 使用来自同一数据集的不同总和在条形图顶部绘制折线图

访问修饰符,命名空间

C#访问修饰符