C# 如何创建确定性guid

C# 如何创建确定性guid,c#,.net,guid,uuid,C#,.net,Guid,Uuid,在我们的应用程序中,我们使用具有Guid值的属性创建Xml文件。此值需要在文件升级之间保持一致。因此,即使文件中的其他内容发生更改,属性的guid值也应保持不变 一个显而易见的解决方案是创建一个静态字典,其中包含文件名和用于它们的guid。然后,无论何时生成文件,我们都会在字典中查找文件名并使用相应的guid。但这是不可行的,因为我们可能会扩展到100个文件,并且不想维护大量的guid 因此,另一种方法是根据文件的路径使Guid相同。由于我们的文件路径和应用程序目录结构是唯一的,因此该路径的Gu

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

一个显而易见的解决方案是创建一个静态字典,其中包含文件名和用于它们的guid。然后,无论何时生成文件,我们都会在字典中查找文件名并使用相应的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; 

} 
因此,给定一个字符串,Guid将始终相同


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

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


顺便说一句,仅仅是个人观点,将md5散列装扮成GUID并不能使它成为一个好的GUID。guid本质上是不确定的。这感觉像是作弊。为什么不直截了当地说它是输入的字符串呈现的散列呢。您可以通过使用此行而不是新的guid行来实现这一点:

string stringHash = BitConverter.ToString(hashBytes)

您需要区分类
Guid
的实例和全局唯一的标识符。“确定性guid”实际上是一个散列(通过调用
provider.ComputeHash
可以证明)。与通过
Guid.NewGuid
创建的Guid相比,哈希值发生冲突的可能性要高得多(两个不同的字符串产生相同的哈希值)

因此,您的方法的问题是,您必须接受两个不同路径将产生相同GUID的可能性。如果您需要一个对于任何给定路径字符串都是唯一的标识符,那么最简单的方法就是使用该字符串。如果您需要对用户隐藏字符串,对其进行加密-您可以使用ROT13或更强大的功能


试图将非纯GUID的内容硬塞进GUID数据类型可能会导致将来的维护问题…

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

on UUID特别允许确定性(基于名称)UUID—版本3和版本5分别使用md5和SHA1。大多数人可能都熟悉版本4,它是随机的。提供了版本的良好概述。(请注意,这里使用的“版本”一词似乎描述了UUID的“类型”——版本5并不取代版本4)

似乎有一些库用于生成3/5版UUID,包括,(C++)和。(我没有寻找任何.net版本)

正如@bacar所提到的,§4.3定义了一种创建基于名称的UUID的方法。这样做的好处(与仅使用MD5哈希相比)是,可以保证这些UUID不会与未命名的UUID发生冲突,并且与其他基于名称的UUID发生冲突的可能性非常(非常)小

在.NET Framework中没有本机支持来创建这些,但是我发布了实现算法的。它可以按如下方式使用:

Guid guid = GuidUtility.Create(GuidUtility.UrlNamespace, filePath);

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

这将把任何字符串转换为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);
}

有更好的方法生成唯一的Guid,但这是一种将字符串数据键一致升级为Guid数据键的方法。

谢谢您的输入,但这仍然会给我一个字符串,我正在寻找Guid…好的,将您的哈希称为“Guid”,问题已解决。或者真正的问题是您需要一个
Guid
对象?我希望它能这么简单:)但是,是的,我需要一个“GUID”对象“GUID本质上是不确定的”——这只适用于某些类型(“版本”)的GUID。然而,我同意@Bradley Grainger和@Rob Fonseca Ensor所说的“将md5散列装扮成GUID并不能成为一个好的GUID”,这也是我对这个问题的回答。这正是最初的海报所追求的。UUID已经有了一个算法,可以让您从字符串开始并将其转换为GUID。UUID版本3使用MD5散列字符串,而版本5使用SHA1散列字符串。创建“guid”的重要一点是使其相对于其他guid“唯一”。该算法定义了两个必须设置的位,以及一个半字节设置为3或5,这取决于它是版本3还是版本5。关于“版本”一词的使用,RFC 4122§4.1.3指出:“版本更准确地说是一个子类型;同样,我们保留了兼容性这一术语。”我发布了一些C代码来在GitHub上创建v3和v5 GUI:@BradleyGrainger,我在符号扩展操作数上得到了警告位or运算符;考虑铸造到一个较小的无符号类型第一,这是离开话题!建议将单个库错误报告移动到GitHub。发现此代码段在使用数据库中的唯一标识符进行联合分发时非常有用。警告!此代码不会生成有效的guid/uuid(正如下面提到的bacar)。版本和类型字段都没有正确设置。使用MD5CryptoServiceProvider而不是SHA1不是同样有效,因为MD5已经有16个字节长了吗?@Porges:RFC4122不正确,并且有修复C代码()的勘误表。如果此实施不完全符合RFC4122及其勘误表,请提供更多详细信息;我想去