C# - 类的通用 HashCode 实现

2023-11-26

我正在研究如何为一个类构建最好的哈希码,我看到了一些算法。我看到了这个:哈希码实现,似乎.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;
    }
}

并像这样使用它:

// 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);
    }
}

总是自己的方法会简单得多,不是吗?我错过了什么吗?


EDIT

根据所有评论,我得到以下代码:

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);
    }
}

您的 Equals 方法已损坏 - 它假设具有相同哈希码的两个对象必然相等。事实并非如此。

乍一看,您的哈希码方法看起来还不错,但实际上可以通过一些工作来完成一些工作 - 见下文。这意味着对任何值类型值进行装箱and任何时候调用它时都会创建一个数组,但除此之外没有问题(正如 SLaks 指出的那样,集合处理存在一些问题)。您可能需要考虑编写一些通用重载,以避免常见情况(可能有 1、2、3 或 4 个参数)的性能损失。您可能还想使用foreach循环而不是普通的for循环,只是为了惯用。

你也可以这样做sort平等的事情,但这会稍微困难和混乱。

编辑:对于哈希码本身,您只需添加值。我suspect你试图做这样的事情:

int hash = 17;
hash = hash * 31 + firstValue.GetHashCode();
hash = hash * 31 + secondValue.GetHashCode();
hash = hash * 31 + thirdValue.GetHashCode();
return hash;

但那个乘以哈希值除以 31,但事实并非如此add31. 目前,对于相同的值,无论它们的顺序是否相同,您的哈希码将始终返回相同的值,这并不理想。

编辑:似乎对于哈希码的用途有些混乱。我建议任何不确定的人阅读文档Object.GetHashCode然后是埃里克·利珀特的关于哈希和相等的博客文章.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# - 类的通用 HashCode 实现 的相关文章

  • 无法使用 strptime() 获取秒数

    我收到 YYYY MM DDThh mm ss S Z hh mm 这种格式的日期时间 我正在尝试使用复制该值strptime如下所示 struct tm time 0 char pEnd strptime datetime Y m dT
  • boost::multi_index_container 复合键中的 equal_range 与比较运算符

    我正在尝试从多索引容器查询结果 其中值类型是三个元素的结构 第一个值已给出 但第二个和第三个值必须大于或小于查询参数 经过搜索后 我发现必须实现自定义密钥提取器 并且这里的一些链接建议相同 但我无法实现它 boost multi index
  • 自动从 C# 代码进行调试过程并读取寄存器值

    我正在寻找一种方法来读取某个地址的 edx 注册表 就像这个问题中所问的那样 读取eax寄存器 https stackoverflow com questions 16490906 read eax register 虽然我的解决方案需要用
  • 如何在 Unity 中从 RenderTexture 访问原始数据

    问题的简短版本 我正在尝试访问 Unity 中 RenderTexture 的内容 我一直在使用 Graphics Blit 使用自己的材质进行绘制 Graphics Blit null renderTexture material 我的材
  • FFMPEG Seeking 带来音频伪影

    我正在使用 ffmpeg 实现音频解码器 在读取音频甚至搜索已经可以工作时 我无法找到一种在搜索后清除缓冲区的方法 因此当应用程序在搜索后立即开始读取音频时 我没有任何工件 avcodec flush buffers似乎对内部缓冲区没有任何
  • SSH 主机密钥指纹与模式 C# WinSCP 不匹配

    我尝试通过 WinSCP 使用 C 连接到 FTPS 服务器 但收到此错误 SSH 主机密钥指纹 与模式不匹配 经过大量研究 我相信这与密钥的长度有关 当使用 服务器和协议信息 下的界面进行连接时 我从 WinSCP 获得的密钥是xx xx
  • Cygwin 下使用 CMake 编译库

    我一直在尝试使用 CMake 来编译 TinyXML 作为一种迷你项目 尝试学习 CMake 作为补充 我试图将其编译成动态库并自行安装 以便它可以工作 到目前为止 我已经设法编译和安装它 但它编译成 dll 和 dll a 让它工作的唯一
  • C# 中值类型和引用类型有什么区别? [复制]

    这个问题在这里已经有答案了 我知道一些差异 值类型存储在堆栈上 而引用类型存储在托管堆上 值类型变量直接包含它们的值 而引用变量仅包含对托管堆上创建的对象位置的引用 我错过了任何其他区别吗 如果是的话 它们是什么 请阅读 堆栈是一个实现细节
  • 写入和读取文本文件 - C# Windows 通用平台应用程序 Windows 10

    有用 但在显示任何内容之前 您必须在文本框中输入内容 我想那是因为我使用了 TextChanged 事件处理程序 如果我希望它在没有用户交互的情况下显示文本文件的内容 我应该使用哪个事件处理程序 因此 我想在按下按钮时将一些数据写入 C W
  • 使用 Google Analytics API 在 C# 中显示信息

    我一整天都在寻找一个好的解决方案 但谷歌发展得太快了 我找不到有效的解决方案 我想做的是 我有一个 Web 应用程序 它有一个管理部分 用户需要登录才能查看信息 在本节中 我想显示来自 GA 的一些数据 例如某些特定网址的综合浏览量 因为我
  • c 中的错误:声明隐藏了全局范围内的变量

    当我尝试编译以下代码时 我收到此错误消息 错误 声明隐藏了全局范围内的变量 无效迭代器 节点 根 我不明白我到底在哪里隐藏或隐藏了之前声明的全局变量 我怎样才能解决这个问题 typedef node typedef struct node
  • .Net Core / 控制台应用程序 / 配置 / XML

    我第一次尝试使用新的 ConfigurationBuilder 和选项模式进入 Net Core 库 这里有很多很好的例子 https docs asp net en latest fundamentals configuration ht
  • 为什么模板不能位于外部“C”块内?

    这是一个后续问题一个答案 https stackoverflow com questions 4866433 is it possible to typedef a pointer to extern c function type wit
  • Windows 10 中 Qt 桌面应用程序的缩放不当

    我正在为 Windows 10 编写一个简单的 Qt Widgets Gui 应用程序 我使用的是 Qt 5 6 0 beta 版本 我遇到的问题是它根本无法缩放到我的 Surfacebook 的屏幕上 这有点难以判断 因为 SO 缩放了图
  • 像“1$”这样的位置参数如何与 printf() 一起使用?

    By man I find printf d width num and printf 2 1 d width num 是等价的 但在我看来 第二种风格应该与以下相同 printf d num width 然而通过测试似乎man是对的 为什
  • 网络参考共享类

    我用 Java 编写了一些 SOAP Web 服务 在 JBoss 5 1 上运行 其中两个共享一个类 AddressTO Web 服务在我的 ApplycationServer 上正确部署 一切都很顺利 直到我尝试在我的 C 客户端中使用
  • char指针或char变量的默认值是什么[重复]

    这个问题在这里已经有答案了 下面是我尝试打印 char 变量和指针的默认值 值的代码 但无法在控制台上看到它 它是否有默认值或只是无法读取 ASCII 范围 include
  • 在Linux中使用C/C++获取机器序列号和CPU ID

    在Linux系统中如何获取机器序列号和CPU ID 示例代码受到高度赞赏 Here http lxr linux no linux v2 6 39 arch x86 include asm processor h L173Linux 内核似
  • Bing 地图运行时错误 Windows 8.1

    当我运行带有 Bing Map 集成的 Windows 8 1 应用程序时 出现以下错误 Windows UI Xaml Markup XamlParseException 类型的异常 发生在 DistanceApp exe 中 但未在用户
  • 将 viewbag 从操作控制器传递到部分视图

    我有一个带有部分视图的 mvc 视图 控制器中有一个 ActionResult 方法 它将返回 PartialView 因此 我需要将 ViewBag 数据从 ActionResult 方法传递到 Partial View 这是我的控制器

随机推荐

  • SceneKit 每个顶点颜色

    我一直在使用 SceneKit 但我不知道如何创建每个顶点颜色几何体 更准确地说 我想这样做 http openglbook com chapter 2 vertices and shapes html 如果不清楚 请告诉我 Thanks
  • 如何让触摸事件影响容器视图后面的视图?

    我有一个完全覆盖另一个 UIView 的容器视图 容器视图具有透明度以及其他一些功能 搜索栏 表格视图等 我希望触摸事件能够通过容器视图 并在事件发生在透明区域时影响下面的视图 我一直在摆弄容器视图的子类 我试图让 pointInside
  • 如何在Windows 10通用应用程序中使用WCF服务?

    我的 Windows 8 1 应用程序使用 WCF 服务 我需要将我的应用程序移植到 Windows 10 UWP 应用程序 但无法添加服务引用 当我添加服务引用时出现此消息 数据服务客户端代码生成失败 不支持指定的 Windows 应用商
  • 如何从字符串数组或数组列表创建字符串?

    我如何提取字符串 或数组列表中的所有元素 并将所有单词以正确的格式 带有单个空格 组合在一起 然后存储在数组中 String a Java is cool 输出 Java 很酷 Use a StringBuilder String stri
  • 如何加快 Eclipse 项目“刷新”速度

    我有一个相当大的 PHP 代码库 10k 文件 我在 Windows 计算机上使用 Eclipse 3 4 PDT 2 来处理它 而这些文件托管在 Debian 文件服务器上 我通过 Windows 上的映射驱动器进行连接 尽管有 1gbi
  • Ruby 相当于 PHP 的 $this

    相当于PHP的什么 this gt 在鲁比 红宝石相当于this is self 它们都指当前实例 棘手的部分是在 Ruby 类范围内 self指的是该类的当前实例Class它定义了您正在构建的类 在方法内部 self指类的实例 eg cl
  • 在 x86-64 中将寄存器移至自身有什么好处

    我正在 x86 64 NASM 中做一个项目 并遇到了指令 mov rdi rdi 在我的教授写的编译器的输出中 我已经进行了全面搜索 但找不到提及为什么需要这样做 它会影响标志还是我不明白的聪明之处 为了提供一些上下文 它在同一寄存器递减
  • Google Analytics API 错误“无法同时查询选定的维度和指标。”

    我必须同时从 GA 电子商务中检索尽可能多的不同指标 我正在使用 google api ruby 客户端 并且不断出现错误 message gt Selected dimensions and metrics cannot be queri
  • 存档上传失败并出现错误:ITMS-90470 缺少 TVTopShelfImage.TVTopShelfPrimaryImageWide 密钥

    您知道为什么会发生这种情况以及最重要的是如何解决它吗 添加具有什么值的密钥 从 tvOS 10 开始 您必须包含宽顶架图像 Top Shelf Image Wide 大小为2320px by 720px 1x tvOS 人机界面指南 图标和
  • 无法加载 share\octave\packages 中可用但未在 share\octave\octave_packages 中列出的包

    短篇故事 在目录中 octave 4 2 1 share octave packages最初有 45 个包子目录 其中 m和其他文件 例如financial 0 5 0 但我找不到使用它们的方法 更详细 我已经解压了便携式 zip 版本Oc
  • 使用 rxjs 实现指数退避

    角7docs提供这个实际用法的例子rxjs Observable为 AJAX 请求实现指数退避 import pipe range timer zip from rxjs import ajax from rxjs ajax import
  • 将rtf或文本文件加载到UITextView iphone sdk中

    嗨 我想知道如何将 rtf 或文本文件加载到 UITextView 中 我使用了几个代码 但不起作用 NSString filePath NSBundle mainBundle pathForResource filename ofType
  • 使用 itext 5.5.5 进行数字签名

    我从 iText 升级5 2 1到iText5 5 5 我使用 PdfStamper 和 PdfSignatureApperance 来应用数字签名 这是我的代码片段 PdfStamper stamper PdfStamper create
  • 第二个 AsyncTask 未执行

    我有 2 个 AsyncTask 一个正在创建套接字连接 另一个正在使用这些套接字传输对象 我的代码是这样的 try connectat true transmitter new SocketTransmitter transmitter
  • 无锁和无锁有什么区别?

    在一些关于算法的文章中 有些使用这个词lockfree 还有一些使用lockless 有什么区别lockless and lockfree 谢谢 Update http www intel com content dam www publi
  • 计算 UITextView 中的行数,按帧大小包裹的行数

    我想知道当文本被文本视图的框架包裹时 是否有任何分隔符可以用来识别文本是否被包裹 例如 如果我的文本视图的宽度为 50 px 并且文本超过该宽度 则会将文本换行到下一行 我想计算文本视图中的行数 现在 n 和 r 对我没有帮助 我的代码是
  • 如何使用私钥将 .pfx 文件转换为密钥库?

    我需要签署 Android 应用程序 apk I have pfx文件 我把它转换为 cer通过 Internet Explorer 文件然后转换 cer to keystore使用密钥工具 然后我尝试签名 apk与 jarsigner 但
  • Spring Boot - 处理 NoHandlerFoundException

    阅读关于如何处理 NoHandlerFoundException 的 Spring 参考指南发现Spring默认设置 throwExceptionIfNoHandlerFound to false 知道了这一点 我认为将此参数设置为一个好主
  • NSWindow 可恢复并不总是有效

    我已经检查了 NSWindow 上的可恢复选项 当我移动应用程序并更改其大小并关闭 重新打开应用程序时 它将窗口大小和位置设置为最后的大小和位置 但这并不是在我测试的每台计算机上都会发生 它只发生在少数计算机上 他们没有关于简历的特殊设置
  • C# - 类的通用 HashCode 实现

    我正在研究如何为一个类构建最好的哈希码 我看到了一些算法 我看到了这个 哈希码实现 似乎 NET类的HashCode方法是类似的 通过反映代码来查看 所以问题是 为什么不创建上面的静态类来自动构建 HashCode 只需传递我们视为 键 的