Можно ли генерировать (очень вероятный) уникальный Integer из GUID?
int i = Guid.NewGuid().GetHashCode();
int j = BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0);
Какой из них лучше?
Можно ли генерировать (очень вероятный) уникальный Integer из GUID?
int i = Guid.NewGuid().GetHashCode();
int j = BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0);
Какой из них лучше?
Эрик Липперт сделал очень интересный (как всегда) пост о вероятности вероятности хеш-коллизий.
Вы должны прочитать все, но он заключил с этой очень показательной графикой:
В связи с вашим конкретным вопросом, я бы тоже пошел с GetHashCode
, поскольку столкновения неизбежны в любом случае.
Функция GetHashCode
специально предназначена для создания хорошо распределенного диапазона целых чисел с низкой вероятностью столкновения, поэтому для этого варианта использования, вероятно, будет лучшее, что вы можете сделать.
Но, как я уверен, вы знаете, хеширование 128 бит информации в 32 бита информации отбрасывает много данных, поэтому почти наверняка будут столкновения, если у вас достаточно большое количество идентификаторов GUID.
Вот простейший способ:
Guid guid = Guid.NewGuid();
Random random = new Random();
int i = random.Next();
Вы заметите, что guid
на самом деле не используется здесь, главным образом потому, что не будет смысла использовать его. Алгоритм Microsoft GUID больше не использует MAC-адрес компьютера - GUID фактически генерируется с использованием псевдослучайного генератора (основанного на значениях времени), поэтому, если вы хотите случайное целое число, имеет смысл использовать класс Random
для этого.
Обновление:, используя GUID для генерации int
, вероятно, будет хуже, чем просто использовать Random
( "хуже" в том смысле, что это скорее сгенерирует коллизии), Это связано с тем, что не все 128 бит в GUID являются случайными. В идеале вы хотели бы исключить не изменяющиеся биты из функции хеширования, хотя было бы намного проще просто создать случайное число, как я уже говорил ранее.:)
GUID - это 128-битное целое число (его только в шестнадцатеричном виде, а не в базе 10). С .NET 4 используйте http://msdn.microsoft.com/en-us/library/dd268285%28v=VS.100%29.aspx так:
// Turn a GUID into a string and strip out the '-' characters.
BigInteger huge = BigInteger.Parse(modifiedGuidString, NumberStyles.AllowHexSpecifier)
Если у вас нет .NET 4, вы можете посмотреть IntX или Solver Foundation.
Поскольку пространство GUID больше, чем число 32-битных целых чисел, у вас гарантировано наличие конфликтов, если у вас достаточно GUID. Учитывая, что вы понимаете это и готовы справиться с столкновениями, как бы редко, GetHashCode() предназначен именно для этой цели и должен быть предпочтительным.
В статическом классе сохраняйте статическую константу integer, затем добавьте 1 к ней перед каждым отдельным доступом (используя свойство public get). Это обеспечит вам цикл всего диапазона int, прежде чем вы получите не уникальное значение.
/// <summary>
/// The command id to use. This is a thread-safe id, that is unique over the lifetime of the process. It changes
/// at each access.
/// </summary>
internal static int NextCommandId
{
get
{
return _nextCommandId++;
}
}
private static int _nextCommandId = 0;
Это приведет к созданию уникального целочисленного значения в текущем процессе. Поскольку вы явно не определяете, насколько уникальным является ваше целое число, это, вероятно, будет соответствовать.
Если вы хотите пробить барьер 2 ^ 32, попробуйте этот метод:
/// <summary>
/// Generate a BigInteger given a Guid. Returns a number from 0 to 2^128
/// 0 to 340,282,366,920,938,463,463,374,607,431,768,211,456
/// </summary>
public BigInteger GuidToBigInteger(Guid guid)
{
BigInteger l_retval = 0;
byte[] ba = guid.ToByteArray();
int i = ba.Count();
foreach (byte b in ba)
{
l_retval += b * BigInteger.Pow(256, --i);
}
return l_retval;
}
Вселенная распадается на холодное и темное пространство, прежде чем столкнется с конфликтом.
Возможно, не целые числа, а маленькие уникальные ключи, в любом случае короче, чем подсказки:
http://www.codeproject.com/Articles/14403/Generating-Unique-Keys-in-Net
У меня было требование, чтобы несколько экземпляров консольного приложения нуждались в получении уникального целочисленного идентификатора. Он используется для идентификации экземпляра и назначается при запуске. Поскольку .exe запускается руками, я решил использовать решение, используя отметки времени начала.
Мое рассуждение состояло в том, что пользователю было бы почти невозможно запустить два .exe в том же миллисекунде. Такое поведение детерминировано: если вы столкнулись с конфликтом, вы знаете, что проблема заключалась в том, что одновременно были запущены два экземпляра. Методы, зависящие от hashcode, GUID или случайных чисел, могут быть непредсказуемыми.
Я устанавливаю дату на 0001-01-01, добавляю текущее время и деля отметки на 10000 (потому что я не устанавливаю микросекунды), чтобы получить число, которое достаточно мало, чтобы вписаться в целое число.
var now = DateTime.Now;
var zeroDate = DateTime.MinValue.AddHours(now.Hour).AddMinutes(now.Minute).AddSeconds(now.Second).AddMilliseconds(now.Millisecond);
int uniqueId = (int)(zeroDate.Ticks / 10000);
ИЗМЕНИТЬ: Есть некоторые оговорки. Чтобы сделать конфликты маловероятными, убедитесь, что: