如何创建确定性指导

Pun*_*ora 96 .net c# uuid guid

在我们的应用程序中,我们使用具有Guid值的属性创建Xml文件.该值必须在文件升级之间保持一致.因此,即使文件中的其他内容发生更改,该属性的guid值也应保持不变.

一个显而易见的解决方案是创建一个静态字典,其中包含文件名和用于它们的Guids.然后每当我们生成文件时,我们都会在字典中查找文件名并使用相应的guid.但这不可行,因为我们可能会扩展到100个文件并且不想保留大量的guid.

所以另一种方法是根据文件的路径使Guid相同.由于我们的文件路径和应用程序目录结构是唯一的,因此Guid对于该路径应该是唯一的.因此,每次我们运行升级时,文件都会根据其路径获得相同的guid.我找到了一种很酷的方法来产生这样的' 确定性指导 '(感谢Elton Stoneman).它基本上是这样的:

private Guid GetDeterministicGuid(string input) 

{ 

//use MD5 hash to get a 16-byte hash of the string: 

MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider(); 

byte[] inputBytes = Encoding.Default.GetBytes(input); 

byte[] hashBytes = provider.ComputeHash(inputBytes); 

//generate a guid from the hash: 

Guid hashGuid = new Guid(hashBytes); 

return hashGuid; 

} 
Run Code Online (Sandbox Code Playgroud)

所以给定一个字符串,Guid将始终是相同的.

有没有其他方法或建议的方法来做到这一点?该方法的优点或缺点是什么?

Bra*_*ger 141

正如@bacar提到的,RFC 4122第4.3节定义了一种方法来创建一个基于名称的UUID.这样做(仅使用MD5哈希)的优点是保证不会与非基于命名的UUID发生冲突,并且与其他基于名称的UUID发生冲突的可能性非常小(非常小).

在.NET Framework中没有用于创建这些的本机支持,但是我在GitHub上发布了实现该算法的代码.它可以使用如下:

Guid guid = GuidUtility.Create(GuidUtility.UrlNamespace, filePath);
Run Code Online (Sandbox Code Playgroud)

为了进一步降低与其他GUID冲突的风险,您可以创建一个私有GUID以用作命名空间ID(而不是使用RFC中定义的URL命名空间ID).

  • @Porges:RFC4122不正确,并有修正C代码的勘误表(http://www.rfc-editor.org/errata_search.php?rfc=4122&eid=1352).如果此实现不完全符合RFC4122及其勘误表,请提供进一步的详细信息; 我想让它遵循标准. (5认同)
  • @Porges:欢迎你/没问题.令人难以置信的是,他们不会使用勘误表中的更正来就地更新RFC.即使是文档末尾的链接也比依赖读者记住搜索勘误表更有帮助(希望*在编写基于RFC的实现之前*). (3认同)
  • @BradleyGrainger:如果您使用 HTML 版本,它会在标题中提供一个指向勘误表的链接,例如 http://tools.ietf.org/html/rfc4122。我想知道是否有浏览器扩展总是重定向到 HTML 版本... (2认同)
  • 你应该考虑将这个贡献给.NET .NET repo在这里:https://github.com/dotnet/coreclr/tree/master/src/mscorlib/src/System (2认同)
  • github 非常适合我,谢谢。这个要点是我所做的修改的副本,目的是删除所有不必要的部分,与命名空间指南无关。https://gist.github.com/angularsen/92a3ba9d9a94d250accd257f9f5a3d54 (2认同)

Ben*_*pka 28

这将把任何字符串转换为Guid,而不必导入外部程序集.

public static Guid ToGuid(string src)
{
    byte[] stringbytes = Encoding.UTF8.GetBytes(src);
    byte[] hashedBytes = new System.Security.Cryptography
        .SHA1CryptoServiceProvider()
        .ComputeHash(stringbytes);
    Array.Resize(ref hashedBytes, 16);
    return new Guid(hashedBytes);
}
Run Code Online (Sandbox Code Playgroud)

有更好的方法来生成唯一的Guid,但这是一种将字符串数据密钥持续升级为Guid数据密钥的方法.

  • 警告!此代码不会生成有效的Guids/UUID(如下面提到的bacar).版本和类型字段都未正确设置. (5认同)
  • 使用MD5CryptoServiceProvider而不是SHA1是否同样有效,因为MD5的长度已经是16个字节? (3认同)

bac*_*car 18

正如Rob提到的,您的方法不会生成UUID,它会生成一个看起来像UUID的哈希.

UUID上的RFC 4122专门允许确定性(基于名称)的UUID - 版本3和5分别使用md5和SHA1.大多数人可能熟悉版本4,这是随机的.维基百科对这些版本进行了很好的概述.(请注意,在这里使用'version'这个词似乎描述了UUID的'type' - 版本5并没有取代版本4).

似乎有一些库用于生成版本3/5 UUID,包括python uuid模块,boost.uuid(C++)和OSSP UUID.(我没有找过任何.net的)

  • 我在GitHub上发布了一些C#代码来创建v3和v5 GUID:https://github.com/LogosBible/Logos.Utility/blob/master/src/Logos.Utility/GuidUtility.cs (10认同)
  • 关于"版本"一词的使用,RFC4122§4.1.3规定:"版本更准确地是一种子类型;同样,我们保留了兼容性这一术语." (2认同)

ryb*_*ber 5

MD5很弱,我相信你可以用SHA-1做同样的事情并获得更好的结果.

顺便说一句,只是个人观点,将md5哈希作为GUID打扮并不能使它成为一个好的GUID.GUID本质上是非确定性的.这感觉就像是作弊.为什么不直接将spade称为spade,只是说它是一个字符串渲染输入的哈希值.你可以通过使用这一行,而不是新的guid线来做到这一点:

string stringHash = BitConverter.ToString(hashBytes)
Run Code Online (Sandbox Code Playgroud)

  • "GUID本质上是非确定性的" - 这仅适用于GUID的某些类型("版本").但是,我同意"由于@Bradley Grainger和@Rob Fonseca-Ensor所阐述的其他原因,将一个md5哈希作为GUID打扮并不能成为一个好的GUID",以及我对这个问题的回答. (4认同)