首页 > 编程语言 >.NET Core应用程序每次启动后使用string.GetHashCode()方法获取到的哈希值(hash)不相同

.NET Core应用程序每次启动后使用string.GetHashCode()方法获取到的哈希值(hash)不相同

时间:2023-07-10 17:36:45浏览次数:49  
标签:Core hash string str 哈希 GetHashCode Console NET

前言

如标题所述,在ASP.NET Core应用程序中,使用string.GetHashCode()方法去获取字符串的哈希值,但每次重启这个ASP.NET Core应用程序之后,同样的字符串的哈希值(hash)但不相同了。这是什么意思呢?

具体的应用场景是这样的: 项目中有一张表的某个字段保存了类似URL这样的字符串,这张表的数据量比较大,而且这个字段会被经常用作检索。所以,为了提高查询效率,在存储的时候同时存储了这个URL字段的哈希值(hash)。

原来ASP.NET MVC 5项目的.NET Framework版本中,随便应用程序怎么重启,使用string.GetHashCode()方法获取到的哈希值永远都是一致的(也需要保持一致)。

但在ASP.NET Core 应用程序中,使用string.GetHashCode()方法,就出现了上述的问题,导致程序在相应的功能部分也出现Bug。最终经过多次测试和查阅资料,定位到了问题的原因。

问题重现

这里我重现一下问题的场景,以下是.NET Framework 4.6.1版本的string.GetHashCode()方法在不断重启程序之后获取到的哈希值(hash),每次获取到的都是相同的值:

复制代码
using System;

namespace ConsoleApp2
{
    class Program
    {
        static void Main()
        {
            var str = "Hello world";
            Console.WriteLine(str.GetHashCode());
            Console.ReadKey();
        }
    }
}
复制代码

输出:-1660742776

但是,如果在.NET Core应用程序中执行以上相同的代码,每次重启程序后获取到的哈希值是不相同的。

比如我重启测试了三次.NET Core应用程序,分别得到了三个不同的哈希值:313140527-11693814872141605647

在定位到问题之后,我们得找出生成不同哈希值的原因。经过一番努力查找之后,其实微软官方文档给出过使用GetHashCode()方法的建议(文档地址)。其中也明确提示了,不应该将使用.NET内置的GetHashCode()方法获取到的值作为持久化的值。

Hash codes are used to insert and retrieve keyed objects from hash tables efficiently. However, hash codes don’t uniquely identify strings. Identical strings have equal hash codes, but the common language runtime can also assign the same hash code to different strings. In addition, hash codes can vary by version of .NET, by platform within a single version, and by application domain. Because of this, you should not serialize or persist hash code values, nor should you use them as keys in a hash table or dictionary.

如何获取一个恒定的哈希值(hash)

那要确保.NET Framework和.NET Core应用程序获取到的哈希值都是相同的,我们需要自定义实现哈希值的算法,以下列出一个可行的算法:

复制代码
public static class HashHelper
{
    public static int GetDeterministicHashCode(this string str)
    {
        unchecked
        {
            int hash1 = (5381 << 16) + 5381;
            int hash2 = hash1;

            for (int i = 0; i < str.Length; i += 2)
            {
                hash1 = ((hash1 << 5) + hash1) ^ str[i];
                if (i == str.Length - 1)
                    break;
                hash2 = ((hash2 << 5) + hash2) ^ str[i + 1];
            }

            return hash1 + (hash2 * 1566083941);
        }
    }
}
复制代码

完整调用示例(.NET Core):

复制代码
using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var str = "Hello world";
            Console.WriteLine(str.GetDeterministicHashCode());
            Console.WriteLine(str.GetDeterministicHashCode());
            Console.WriteLine(str.GetDeterministicHashCode());
            Console.WriteLine("****************************");
            Console.WriteLine(str.GetHashCode());
            Console.WriteLine(str.GetHashCode());
            Console.WriteLine(str.GetHashCode());
            Console.ReadKey();
        }
    }

    public static class HashHelper
    {
        public static int GetDeterministicHashCode(this string str)
        {
            unchecked
            {
                int hash1 = (5381 << 16) + 5381;
                int hash2 = hash1;

                for (int i = 0; i < str.Length; i += 2)
                {
                    hash1 = ((hash1 << 5) + hash1) ^ str[i];
                    if (i == str.Length - 1)
                        break;
                    hash2 = ((hash2 << 5) + hash2) ^ str[i + 1];
                }

                return hash1 + (hash2 * 1566083941);
            }
        }        
    }
}
复制代码

 

     

标签:Core,hash,string,str,哈希,GetHashCode,Console,NET
From: https://www.cnblogs.com/webenh/p/17541773.html

相关文章

  • 周一 toString
    在Java类中,toString()方法用于返回表示该对象文本描述的字符串。这个方法通常被用于调试和打印输出。当使用System.out.println()方法打印对象时,实际上是调用了该对象的toString()方法来获取表示它的字符串形式。toString()方法的含义是为了提供一个有意义的、可读性好的字符串表......
  • LWC 50:678. Valid Parenthesis String
    LWC50:678.ValidParenthesisString传送门:678.ValidParenthesisStringProblem:Givenastringcontainingonlythreetypesofcharacters:‘(‘,‘)’and‘*’,writeafunctiontocheckwhetherthisstringisvalid.Wedefinethevalidityofastringbythese......
  • String s=new String(“hello”)的执行过程
    一.介绍String是Java.long包下的String类,是一个特殊的引用类型,用于表示字符串。它提供了许多方法来操作和处理字符串,比如连接、截取、查找、替换等。String类内部使用字符数组(char[])来存储字符串的内容,value字段被final修饰,String对象一旦创建后,其值就不可改变。Strin......
  • HashMap 源码阅读
    HashMap源码阅读HashMap是线程不安全的,若需要考虑线程安全则需要用HashTable属性//默认大小1<<4为16staticfinalintDEFAULT_INITIAL_CAPACITY=1<<4;//最大2的30次方staticfinalintMAXIMUM_CAPACITY=1<<30;//默认负载因子0.75staticfinal......
  • String 源码阅读
    String源码阅读1.属性/**Thevalueisusedforcharacterstorage.*/privatefinalcharvalue[];/**Cachethehashcodeforthestring*/privateinthash;//Defaultto0/**useserialVersionUIDfromJDK1.0.2forinteroperability*/privatestaticfi......
  • CF559B - Equivalent Strings
    首先我们考虑第一种做法,我们搜索\(dp_{x,y,l,r}\)判断\(s[x,y]\)和\(t[l,r]\)是否等价,同时记忆化搜索。但是这样是很明显不行的。如果长度是\(2\)的整次幂,我们仅分析最底层长度为\(1\)的区间,我们发现,任何的\([x,x][y,y](x\len/2)\),都会被搜到一遍。这个可以递归处理,......
  • Hash 学习笔记与总结
    Hash算法学习笔记与总结目录Hash字符串Hash信息学奥赛一本通AcWing模板模板题题目大意CODEHash表拉链法开放寻址法模板题题目大意CODEHash哈希算法是通过一个哈希函数H,将一种数据(包活字符串、较大的数等)转化为能够用变量表示或是直接就可作为数组下标的数,道过哈希函数......
  • .Net Core Jwt鉴权授权
    目录简介基于.NetCore验证方式Jwt获取Token引入三方包生成TokenUserInfoJwtConfigWebApi测试(获取Token)Program.csappsetting.jsonController.NetCore验证(webApi)ProgarmContorller.NetCore授权简介Program.csJwtAuthorization.cs注意Autofac注册授权服务Controller注意......
  • python-opencv核心库模块core(下)
    本章节主要记录opencv核心库模块core的图像旋转,图像拼接,图像仿射变换,图像roi区域提取和图像傅里叶变换等操作。1图像旋转opencv提供了将图像沿着坐标轴旋转的函数flip,dst=flip(src,flipcode) flipcode表示旋转的标志,等于0表示沿着x轴旋转,正数表示沿着y轴旋转,负数表示沿着x......
  • String、StringBuffer、StringBuilder 的区别?
    一.介绍String、StringBuffer、StringBuilder:  前言: String、StringBuffer、StringBuilder均在java.lang包下;String: 在Java中,String是一个特殊的引用类型,用于表示文本字符串。它提供了许多方法来操作和处理字符串,比如连接、截取、查找、替换等。String类......