目录

介绍

背景

哈希助手类

考虑

对象到哈希字符串的过程

多个对象组合的哈希

我们将更频繁地使用的方法

整个对象的哈希

重要的是记住

数据值散列

哈希结果

其他测试

奖励:字符串哈希

结论


  • 下载源代码 - 5.9 KB

介绍

散列是将值转换为通常较短的固定长度的键/值,其表示原始值。几天前,我们不得不使用哈希比较来通过API在两个系统之间同步数据(显然,这不是使用API​​进行数据同步的最有效方式,但我们没有选择在源端添加任何更改) 。

背景

我们在做什么:

  1. 在对象JSON反序列化之后在我们的末尾创建一个哈希字符串
  2. 通过唯一标识符(主键)将该哈希字符串与现有数据库行进行比较
    1. 如果唯一标识符(主键)找不到行,则向DB添加新行
    2. 如果哈希字符串不相同,则使用新值更新现有行
  3. 还有其他几个同步日志进程

一切都按预期工作,直到我们重构现有代码(更改了一些模型和属性的名称)。哈希字符串是从整个对象(包括所有值)生成的,而不是考虑特定的属性。我们创建哈希字符串的方式实际上是错误的。我们来看几个哈希字符串示例。

哈希助手类

这是用于管理与哈希相关的操作的实用程序类。

using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography;
using System.Text;public class HashHelper
{/// <summary>/// for custom class need [Serializable]/// to ignore https://stackoverflow.com/questions/33489930//// ignore-non-serialized-property-in-binaryformatter-serialization/// </summary>/// <param name="value"></param>/// <returns></returns>public byte[] Byte(object value){/*https://stackoverflow.com/questions/1446547/how-to-convert-an-object-to-a-byte-array-in-c-sharp*/using (var ms = new MemoryStream()){BinaryFormatter bf = new BinaryFormatter();bf.Serialize(ms, value == null ? "null" : value);return ms.ToArray();}}public byte[] Hash(byte[] value){/*https://support.microsoft.com/en-za/help/307020/how-to-compute-and-compare-hash-values-by-using-visual-cs*//*https://andrewlock.net/why-is-string-gethashcode-different-each-time-i-run-my-program-in-net-core*/byte[] result = MD5.Create().ComputeHash(value);return result;}public byte[] Combine(params byte[][] values){/*https://stackoverflow.com/questions/415291/best-way-to-combine-two-or-more-byte-arrays-in-c-sharp*/byte[] rv = new byte[values.Sum(a => a.Length)];int offset = 0;foreach (byte[] array in values){System.Buffer.BlockCopy(array, 0, rv, offset, array.Length);offset += array.Length;}return rv;}public string String(byte[] hash){/*https://stackoverflow.com/questions/1300890/md5-hash-with-salt-for-keeping-password-in-db-in-c-sharp*/StringBuilder sb = new StringBuilder();for (int i = 0; i < hash.Length; i++){sb.Append(hash[i].ToString("x2"));     /*do not make it X2*/}var result = sb.ToString();return result;}public byte[] Hash(params object[] values){byte[][] bytes = new byte[values.Length][];for(int i=0; i < values.Length; i++){bytes[i] = Byte(values[i]);}byte[] combined = Combine(bytes);byte[] combinedHash = Hash(combined);return combinedHash;}/*https://stackoverflow.com/questions/5868438/c-sharp-generate-a-random-md5-hash*/public string HashString(string value, Encoding encoding = null){if (encoding == null){encoding = Encoding.ASCII;}byte[] bytes = encoding.GetBytes(value);byte[] hash = Hash(bytes);string result = String(hash);return result;}public string HashString(params object[] values){var hash = Hash(values);    /*Add more not constant properties as needed*/var value = String(hash);return value;}
}

考虑

  • 使用MD5哈希Hash(byte[] value)
  • 任何null 值都被视为'null'字符串Byte(object value)

对象到哈希字符串的过程

  1. 创建该对象的字节 Byte(object value)
  2. 从对象字节Hash(byte[] value)创建哈希字节
  3. 散列字节String(byte[] hash)中返回的字符串

多个对象组合的哈希

  1. 创建每个对象的字节 Byte(object value)
  2. 将字节组合或求和 Combine(params byte[][] values)
  3. 从组合创建哈希字节或对字节求和 Hash(byte[] value)
  4. 散列字节String(byte[] hash)中返回的字符串

或者:

  1. 创建组合哈希字节 Hash(params object[] values)
  2. 散列字节String(byte[] hash)中返回的字符串

我们将更频繁地使用的方法

  • 创建任何字符串的哈希字符串 HashString(string value, Encoding encoding = null)
  • 创建任何/对象组的哈希/组合哈希字符串 HashString(params object[] values)

整个对象的哈希

数据类或模型:

[Serializable]
class PeopleModel
{public long? Id { get; set; }public string Name { get; set; }public bool? IsActive { get; set; }public DateTime? CreatedDateTime { get; set; }
}

创建模型的哈希:

/*9105d073ad276d742c56a049abd4ddef* will change if we change *      1. class name*      2. property name*      3. property data type*      4. add/remove new property etc*/
var peopleModelHashString = hashHelper.HashString(new PeopleModel()
{Id = 1,Name = "Anders Hejlsberg",IsActive = true,CreatedDateTime = new DateTime(1960, 12, 2)
});

重要的是记住

此哈希取决于对象结构和分配的值。即使我们为属性分配相同的值,生成的哈希也不会相同,但添加了一些更改,如:

  • 类/模型名称更改
  • 属性名称更改
  • 命名空间名称更改
  • 属性编号更改(添加或删除任何属性)

到模型。而在开发环境中,重构可能发生的任何时间。

数据值散列

让我们只使用值进行哈希。创建一个接口IHash。

public interface IHash
{string HashString();
}

使用IHash到模型并在方法HashString()内部使用哈希助手。

class People : IHash
{public long? Id { get; set; }         /*unique identifier, avoid it to use in hash calculation*/public string Name { get; set; }public bool? IsActive { get; set; }public DateTime? CreatedDateTime { get; set; }public string HashString(){var value = new HashHelper().HashString(Name, IsActive, CreatedDateTime);    /*Add more not constant properties as needed*/return value;}
}

这样,模型结构不参与哈希生成过程中,只有特定的属性值(Name,IsActive,CreatedDateTime)正被考虑。

Hash将保持不变,直到没有为这些属性设置任何新值。模型的任何结构更改(名称更改,属性添加/删除等)都不会影响哈希字符串。

哈希结果

/*constant: 3953fbec5b81ccca72c98655c0c4b069*/
people = new People()
{Id = 1,Name = "Dennis Ritchie",IsActive = false,CreatedDateTime = new DateTime(1941, 9, 9)
};
hashString = people.HashString();

其他测试

使用null 对象值正常工作:

string hashString;
/*constant: 47ccecfc14f9ed9eff5de591b8614077*/
var people = new People();
hashString = people.HashString();

我们将无法创建整个People类,因为它不使用[Serializable]:

var hashHelper = new HashHelper();
/*throws error as [Serializable] not been used*/
//var peopleHashString = hashHelper.HashString(people);

奖励:字符串哈希

创建密码/字符串哈希是很常见的。所以我们拥有它。

/*constant: e6fb7af54c39f39507c28a86ad98a1fd*/
string name = "Dipon Roy";
string value = new HashHelper().HashString(name);

结论

  • 如果我们只需要比较考虑值或特定值,那么使用数据值哈希是最佳选择。
  • 但是如果我们需要完全比较对象结构和值,请选择整个对象的哈希

原文地址:https://www.codeproject.com/Tips/5130239/Csharp-Generating-Hash-String

C#:生成哈希字符串相关推荐

  1. Python 生成文件或字符串的 sha256

    例子当然要简洁,废话当然要少说,这块主要以 sha256 为例来进行说明,当然你可以选择 sha512 .md5 等其他算法! 文件的 sha256 这里唯一要注意的一点:文件一定要以二进制的形式打开 ...

  2. java 字符串转哈希_从哈希字符串转换字节,java与python

    我在将纯java Curve25519函数转换为Python等效函数时遇到问题,具体问题与将哈希字符串转换为等效字节的摘要函数有关,java实现: 数据示例: sP="这是用于测试的密码短语 ...

  3. ruby 生成哈希值_Ruby哈希值和可变的默认值

    ruby 生成哈希值 Ruby's Hash object is an associative data structure used to store key-value pairs. Many l ...

  4. 生成24位字符串ID__IdGenerator.java

    此工具类用于生成24位字符串ID,唯一不重复. 直接通过 IdGenerator.get() 获取. 源码如下:(点击下载源码 - IdGenerator.java ) 1 import java.n ...

  5. python使用fpdf将生成的长字符串手动换行写入pdf

    python使用fpdf将生成的长字符串手动换行写入pdf 目录 python使用fpdf将生成的长字符串手动换行写入pdf #lassocv生成特征系数dataframe

  6. python使用textwrap包在已经生成的长字符串中嵌入回车符实战

    python使用textwrap包在已经生成的长字符串中嵌入回车符实战 目录 python使用textwrap包在已经生成的长字符串中嵌入回车符实战 # textwrap包在长字符串中嵌入回车符 #实 ...

  7. Android程序获得APP哈希值,Android – SMS Retriever API – 计算应用程序的哈希字符串问题...

    我是Android的新手,我正在尝试实现SMS Retriever API,以便在我的应用中使用OTP. 不幸的是,我陷入了"计算你的应用程序的哈希字符串"的部分 我在这里引用了指 ...

  8. boost :: hash_combine从类的不同成员生成哈希值

    boost :: hash_combine从类的不同成员生成哈希值 实现功能 C++实现代码 实现功能 Boost的container_hash模块,boost :: hash_combine从类的不 ...

  9. ruby 生成哈希值_哈希== Ruby中的运算符

    ruby 生成哈希值 In the last article, we have seen how we can compare two hash objects with the help of &l ...

最新文章

  1. 神经正切核,深度学习理论研究的最新热点?
  2. NetDevOps — PyEZ
  3. java mysql 分布式锁_Java分布式锁之数据库方式实现
  4. Spring可扩展Schema标签
  5. Finding Gems
  6. Java中Thread类的方法简介
  7. 49 SD配置-定价配置-定义条件类型
  8. Leetcode 1219.黄金矿工
  9. 使用Windows迁移工具迁移2003至2012R2 二、IP迁移
  10. java坦克大战爆炸效果_Java坦克大战第一个坦克不爆炸问题
  11. 组网[ZeroTier]+自建Moon服务
  12. 各种说明方法的例句_举例子,列数字,作比较,打比方,这几个说明方法的例句...
  13. xss.haozi靶场通关
  14. 虚拟机挂载优盘和识别优盘
  15. 微信小程序与公众号区别PHP,微信小程序和微信公众号的区别是什么?
  16. 计量经济学笔记5-Eviews操作-异方差的检验与消除(White检验与加权最小二乘)
  17. CCC认证费用是多少?
  18. Stopwatch常用方法,不积硅步无以至千里
  19. eCharts.js使用心得
  20. 高保真Axure原型设计实战 - 自适应后台框架

热门文章

  1. hadoopsdk使用_使用 IDEA 搭建 Hadoop3.1.1 项目
  2. 如何在设计项目中使用冷调酷色
  3. 壁纸图片|2020年12月游戏图片大全
  4. 设计灵感合集|拟人化创意合成小动物,治愈可爱风插画作品
  5. 就知道你会没灵感,感恩节psd分层海报模板来咯!
  6. UI设计素材模板|设计良好的教育网站:3个快捷技巧
  7. UI素材实用模板|2.5D等距风格插画专辑
  8. lambert(兰伯特)投影 应用工具_全息投影技术,在哪些场地可以用到
  9. python合法的变量名有哪些_Python判断变量名是否合法的方法示例
  10. asp.net 添加权限