Как создать детерминированную идентификаторы GUID
в нашем приложении мы создаем Xml-файлы с атрибутом, который имеет значение Guid. Это значение должно быть согласовано между обновлениями файлов. Поэтому, даже если все остальное в файле изменится, значение guid для атрибута должно остаться прежним.
таким образом, другой подход состоял в том, чтобы сделать Guid таким же, основываясь на пути к файлу. Поскольку наши пути к файлам и структура каталогов приложений уникальны, Guid должен быть уникальным для этого пути. Поэтому каждый раз, когда мы запускаем обновление, файл получает один и тот же идентификатор guid на основе его пути. Я нашел один классный способ генерировать такие'Детерминированные Идентификаторы GUID' (Спасибо Элтон Стоунмен). Он в основном делает это:
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 всегда будет одинаковым.
есть ли другие подходы или рекомендуемые способы сделать это? Какие плюсы или минусы этого метода?
5 ответов:
Как упоминалось @bacar,RFC 4122 §4.3 определяет способ создания UUID на основе имени. Преимущество этого (по сравнению с просто использованием хэша MD5) заключается в том, что они гарантированно не сталкиваются с безымянными UUID и имеют очень (очень) небольшую возможность столкновения с другими UUID на основе имен.
в .NET Framework нет собственной поддержки для их создания, но я опубликовал код на GitHub, который реализует алгоритм. Он может быть использован в качестве следует:
Guid guid = GuidUtility.Create(GuidUtility.UrlNamespace, filePath);чтобы еще больше снизить риск конфликтов с другими идентификаторами GUID, можно создать частный идентификатор GUID для использования в качестве идентификатора пространства имен (вместо использования идентификатора пространства имен URL, определенного в RFC).
это преобразует любую строку в 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.
Как упоминает Роб, ваш метод не генерирует UUID, он генерирует хэш, который выглядит как UUID.
The RFC 4122 на UUIDs специально позволяет для детерминированных(на основе имен) UUIDs-версии 3 и 5 используют md5 и SHA1 (соответственно). Большинство людей, вероятно, знакомы с версией 4, которая является случайной. Википедия дает хороший обзор версии. (Заметьте, что использование версии слово здесь, кажется, чтобы описать тип, идентификатор UUID - версия 5 не заменяет версию 4).
там, кажется, есть несколько библиотек для генерации версии 3/5 UUIDs, в том числе модуль python uuid,импульс.uuid (C++) и OSP UUID. (Я не искал никаких .net)
MD5 слаб, я считаю, что вы можете сделать то же самое с SHA-1 и получить лучшие результаты.
кстати, просто личное мнение, одевание хэша md5 в качестве GUID не делает его хорошим GUID. GUID по своей природе не детерминированы. это похоже на обман. Почему бы просто не назвать лопату лопатой и просто сказать, что это строка, отображаемая хэшем ввода. вы можете сделать это, используя эту строку, а не новую строку guid:
string stringHash = BitConverter.ToString(hashBytes)
вы должны сделать различие между экземплярами класса
Guid, и идентификаторы, которые являются уникальными во всем мире. "Детерминированный guid" на самом деле является хэшем (о чем свидетельствует ваш звонок вprovider.ComputeHash). Хэши имеют гораздо более высокую вероятность столкновений (две разные строки, которые производят один и тот же хэш), чем Guid, созданный черезGuid.NewGuid.Так что проблема с вашим подходом заключается в том, что вы должны быть в порядке с возможностью того, что два разных пути будут производить то же самое идентификатор GUID. Если вам нужен идентификатор, который уникален для любой заданной строки пути, то проще всего сделать это просто используйте строку. Если вам нужно, чтобы строка была скрыта от ваших пользователей,зашифровать его - вы можете использовать ROT13 или что-то более мощное...
попытка вставить что-то, что не является чистым GUID в тип данных GUID, может привести к проблемам обслуживания в будущем...
Comments