Мне нужен уникальный идентификатор в .NET (нельзя использовать GUID, так как он слишком длинный для этого случая).
Считают ли люди, что используемый здесь алгоритм является хорошим кандидатом, или у вас есть другие предложения?
c#
.net
uniqueidentifier
Ноэль
источник
источник
Ответы:
Хороший - http://www.singular.co.nz/blog/archive/2007/12/20/shortguid-a-shorter-and-url-friendly-guid-in-c-sharp.aspx
а также здесь YouTube-подобный GUID
Вы можете использовать Base64:
string base64Guid = Convert.ToBase64String(Guid.NewGuid().ToByteArray());
источник
Я использую тот же подход, что и у Дора Коэна, но удаляю некоторые специальные символы:
var uid = Regex.Replace(Convert.ToBase64String(Guid.NewGuid().ToByteArray()), "[/+=]", "");
Это выведет только буквенно-цифровые символы. Не гарантируется, что UID всегда будут иметь одинаковую длину. Вот пример выполнения:
vmKo0zws8k28fR4V4Hgmw TKbhS0G2V0KqtpHOU8e6Ug rfDi1RdO0aQHTosh9dVvw 3jhCD75fUWjQek8XRmMg CQUg1lXIXkWG8KDFy7z6Ow bvyxW5aj10OmKA5KMhppw pIMK8eq5kyvLK67xtsIDg VX4oljGWpkSQGR2OvGoOQ NOHBjUUHv06yIc7EvotRg iMniAuUG9kiGLwBtBQByfg
источник
var ticks = new DateTime(2016,1,1).Ticks; var ans = DateTime.Now.Ticks - ticks; var uniqueId = ans.ToString("x");
Сохраните базовую дату (в данном случае 1 января 2016 г.), с которой вы начнете генерировать эти идентификаторы. Это уменьшит ваши идентификаторы.
Сгенерированный номер: 3af3c14996e54
источник
milliseconds
всегда 0 для этогоDateTime
объектаПростой в использовании пакет. Я использую его для генератора временных идентификаторов запросов.
https://www.nuget.org/packages/shortid
https://github.com/bolorundurowb/shortid
Использует
System.Random
string id = ShortId.Generate(); // id = KXTR_VzGVUoOY
(со страницы github)
Если вы хотите управлять типом генерируемого идентификатора, указав, нужны ли вам числа, специальные символы и длину, вызовите метод Generate и передайте три параметра, первый из которых является логическим, указывающим, хотите ли вы числа, а второй - логическим, указывающим, хотите ли вы специальные символы, последняя цифра указывает вашу предпочтительную длину.
string id = ShortId.Generate(true, false, 12); // id = VvoCDPazES_w
источник
Насколько я знаю, простое удаление части GUID не гарантирует уникальности - на самом деле, это далеко не так.
Самая короткая вещь, которую я знаю, которая гарантирует глобальную уникальность, описана в этой записи блога Джеффа Этвуда . В связанном посте он обсуждает несколько способов сокращения GUID и, в конце концов, сокращает его до 20 байт с помощью кодировки Ascii85 .
Однако, если вам абсолютно необходимо решение, длина которого не превышает 15 байт, боюсь, у вас нет другого выбора, кроме как использовать что-то, что не гарантированно будет глобально уникальным.
источник
Значения IDENTITY должны быть уникальными в базе данных, но вы должны знать об ограничениях ... например, это делает невозможным массовую вставку данных, что замедлит вас, если вы работаете с очень большим количеством записей.
Вы также можете использовать значение даты / времени. Я видел несколько баз данных, в которых дата / время используются в качестве ПК, и хотя это не очень чисто, но работает. Если вы управляете вставками, вы можете эффективно гарантировать, что значения будут уникальными в коде.
источник
Для моего локального приложения я использую этот подход, основанный на времени:
/// <summary> /// Returns all ticks, milliseconds or seconds since 1970. /// /// 1 tick = 100 nanoseconds /// /// Samples: /// /// Return unit value decimal length value hex length /// -------------------------------------------------------------------------- /// ticks 14094017407993061 17 3212786FA068F0 14 /// milliseconds 1409397614940 13 148271D0BC5 11 /// seconds 1409397492 10 5401D2AE 8 /// /// </summary> public static string TickIdGet(bool getSecondsNotTicks, bool getMillisecondsNotTicks, bool getHexValue) { string id = string.Empty; DateTime historicalDate = new DateTime(1970, 1, 1, 0, 0, 0); if (getSecondsNotTicks || getMillisecondsNotTicks) { TimeSpan spanTillNow = DateTime.UtcNow.Subtract(historicalDate); if (getSecondsNotTicks) id = String.Format("{0:0}", spanTillNow.TotalSeconds); else id = String.Format("{0:0}", spanTillNow.TotalMilliseconds); } else { long ticksTillNow = DateTime.UtcNow.Ticks - historicalDate.Ticks; id = ticksTillNow.ToString(); } if (getHexValue) id = long.Parse(id).ToString("X"); return id; }
источник
здесь мое решение небезопасно для параллелизма, не более 1000 GUID в секунду и потокобезопасно.
public static class Extensors { private static object _lockGuidObject; public static string GetGuid() { if (_lockGuidObject == null) _lockGuidObject = new object(); lock (_lockGuidObject) { Thread.Sleep(1); var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); var epochLong = Convert.ToInt64((DateTime.UtcNow - epoch).TotalMilliseconds); return epochLong.DecimalToArbitrarySystem(36); } } /// <summary> /// Converts the given decimal number to the numeral system with the /// specified radix (in the range [2, 36]). /// </summary> /// <param name="decimalNumber">The number to convert.</param> /// <param name="radix">The radix of the destination numeral system (in the range [2, 36]).</param> /// <returns></returns> public static string DecimalToArbitrarySystem(this long decimalNumber, int radix) { const int BitsInLong = 64; const string Digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; if (radix < 2 || radix > Digits.Length) throw new ArgumentException("The radix must be >= 2 and <= " + Digits.Length.ToString()); if (decimalNumber == 0) return "0"; int index = BitsInLong - 1; long currentNumber = Math.Abs(decimalNumber); char[] charArray = new char[BitsInLong]; while (currentNumber != 0) { int remainder = (int)(currentNumber % radix); charArray[index--] = Digits[remainder]; currentNumber = currentNumber / radix; } string result = new String(charArray, index + 1, BitsInLong - index - 1); if (decimalNumber < 0) { result = "-" + result; } return result; }
код не оптимизирован, просто образец !.
источник
UtcNow
возвращает уникальное значение тика для каждой миллисекунды: согласно примечаниям , разрешение зависит от системного таймера. Кроме того, вам лучше убедиться, что системные часы не меняются назад! (Поскольку ответ user13971889 поднял этот вопрос в начало моей ленты, и я критиковал этот ответ, я полагаю, что должен повторить эту критику здесь.)Если в вашем приложении нет нескольких МИЛЛИОНОВ человек, которые генерируют короткую уникальную строку в ТО ЖЕ МИЛЛИСЕКУНДУ, вы можете подумать об использовании функции ниже.
private static readonly Object obj = new Object(); private static readonly Random random = new Random(); private string CreateShortUniqueString() { string strDate = DateTime.Now.ToString("yyyyMMddhhmmssfff"); string randomString ; lock (obj) { randomString = RandomString(3); } return strDate + randomString; // 16 charater } private string RandomString(int length) { const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxy"; var random = new Random(); return new string(Enumerable.Repeat(chars, length) .Select(s => s[random.Next(s.Length)]).ToArray()); }
измените yyyy на yy, если вам просто нужно использовать свое приложение в следующие 99 лет.
Обновление 20160511 : функция Correct Random
- Добавить объект Lock
- Переместить случайную величину из функции RandomString
Ссылка
источник
lock
, чтобы позволить вам повторно использовать один и тот жеRandom
экземпляр. Я думаю, вы забыли удалить эту строку!Я знаю, что это довольно далеко от даты публикации ... :)
У меня есть генератор, который производит только 9 символов Hexa, например: C9D6F7FF3, C9D6FB52C
public class SlimHexIdGenerator : IIdGenerator { private readonly DateTime _baseDate = new DateTime(2016, 1, 1); private readonly IDictionary<long, IList<long>> _cache = new Dictionary<long, IList<long>>(); public string NewId() { var now = DateTime.Now.ToString("HHmmssfff"); var daysDiff = (DateTime.Today - _baseDate).Days; var current = long.Parse(string.Format("{0}{1}", daysDiff, now)); return IdGeneratorHelper.NewId(_cache, current); } } static class IdGeneratorHelper { public static string NewId(IDictionary<long, IList<long>> cache, long current) { if (cache.Any() && cache.Keys.Max() < current) { cache.Clear(); } if (!cache.Any()) { cache.Add(current, new List<long>()); } string secondPart; if (cache[current].Any()) { var maxValue = cache[current].Max(); cache[current].Add(maxValue + 1); secondPart = maxValue.ToString(CultureInfo.InvariantCulture); } else { cache[current].Add(0); secondPart = string.Empty; } var nextValueFormatted = string.Format("{0}{1}", current, secondPart); return UInt64.Parse(nextValueFormatted).ToString("X"); } }
источник
На основе ответа @dorcohen и комментария @pootzko. Вы можете использовать это. Это безопасно по проводу.
var errorId = System.Web.HttpServerUtility.UrlTokenEncode(Guid.NewGuid().ToByteArray());
источник
Jzhw2oVozkSNa2IkyK4ilA2
или попробуйте себя на dotnetfiddle.net/VIrZ8jОсновываясь на некоторых других, вот мое решение, которое предоставляет другой кодированный guid, который является безопасным для URL (и Docker) и не теряет никакой информации:
Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Replace("=", "").Replace("+", "-").Replace("/", "_");
Примеры результатов:
источник
В C #
long
значение имеет 64 бита, которые при кодировании с помощью Base64 будут содержать 12 символов, включая 1 заполнение=
. Если мы обрежем отступ=
, будет 11 символов.Одна безумная идея заключается в том, что мы могли бы использовать комбинацию Unix Epoch и счетчика для одного значения эпохи, чтобы сформировать
long
значение. Эпоха Unix в C #DateTimeOffset.ToUnixEpochMilliseconds
имеетlong
формат, но первые 2 байта из 8 всегда равны 0, потому что в противном случае значение даты и времени будет больше, чем максимальное значение даты и времени. Это дает нам 2 байта для размещенияushort
счетчика.Итак, в целом, если количество генераций идентификаторов не превышает 65536 за миллисекунду, мы можем иметь уникальный идентификатор:
// This is the counter for current epoch. Counter should reset in next millisecond ushort currentCounter = 123; var epoch = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); // Because epoch is 64bit long, so we should have 8 bytes var epochBytes = BitConverter.GetBytes(epoch); if (BitConverter.IsLittleEndian) { // Use big endian epochBytes = epochBytes.Reverse().ToArray(); } // The first two bytes are always 0, because if not, the DateTime.UtcNow is greater // than DateTime.Max, which is not possible var counterBytes = BitConverter.GetBytes(currentCounter); if (BitConverter.IsLittleEndian) { // Use big endian counterBytes = counterBytes.Reverse().ToArray(); } // Copy counter bytes to the first 2 bytes of the epoch bytes Array.Copy(counterBytes, 0, epochBytes, 0, 2); // Encode the byte array and trim padding '=' // e.g. AAsBcTCCVlg var shortUid = Convert.ToBase64String(epochBytes).TrimEnd('=');
источник
public static string ToTinyUuid(this Guid guid) { return Convert.ToBase64String(guid.ToByteArray())[0..^2] // remove trailing == padding .Replace('+', '-') // escape (for filepath) .Replace('/', '_'); // escape (for filepath) }
Применение
Обратное преобразование - это не ракетостроение, поэтому я оставлю вам это.
источник
Если вам не нужно вводить строку, вы можете использовать следующее:
static class GuidConverter { public static string GuidToString(Guid g) { var bytes = g.ToByteArray(); var sb = new StringBuilder(); for (var j = 0; j < bytes.Length; j++) { var c = BitConverter.ToChar(bytes, j); sb.Append(c); j++; } return sb.ToString(); } public static Guid StringToGuid(string s) => new Guid(s.SelectMany(BitConverter.GetBytes).ToArray()); }
Это преобразует Guid в строку из 8 символов, например:
{b77a49a5-182b-42fa-83a9-824ebd6ab58d} -> "䦥 띺 ᠫ 䋺 ꦃ 亂 檽 趵"
{c5f8f7f5-8a7c-4511-b667-8ad36b446617} -> " 엸 詼 䔑 架 펊 䑫 ᝦ"
источник
Вот мой небольшой метод для генерации случайного и короткого уникального идентификатора. Использует криптографический rng для безопасной генерации случайных чисел. Добавьте в
chars
строку любые символы, которые вам нужны .private string GenerateRandomId(int length) { char[] stringChars = new char[length]; byte[] randomBytes = new byte[length]; using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) { rng.GetBytes(randomBytes); } string chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; for (int i = 0; i < stringChars.Length; i++) { stringChars[i] = chars[randomBytes[i] % chars.Length]; } return new string(stringChars); }
источник
чтобы не терять символы (+ / -), и если вы хотите использовать свой guid в URL-адресе, он должен быть преобразован в base32
на 10 000 000 без дубликата ключа
public static List<string> guids = new List<string>(); static void Main(string[] args) { for (int i = 0; i < 10000000; i++) { var guid = Guid.NewGuid(); string encoded = BytesToBase32(guid.ToByteArray()); guids.Add(encoded); Console.Write("."); } var result = guids.GroupBy(x => x) .Where(group => group.Count() > 1) .Select(group => group.Key); foreach (var res in result) Console.WriteLine($"Duplicate {res}"); Console.WriteLine($"*********** end **************"); Console.ReadLine(); } public static string BytesToBase32(byte[] bytes) { const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; string output = ""; for (int bitIndex = 0; bitIndex < bytes.Length * 8; bitIndex += 5) { int dualbyte = bytes[bitIndex / 8] << 8; if (bitIndex / 8 + 1 < bytes.Length) dualbyte |= bytes[bitIndex / 8 + 1]; dualbyte = 0x1f & (dualbyte >> (16 - bitIndex % 8 - 5)); output += alphabet[dualbyte]; } return output; }
источник
Вы можете попробовать следующую библиотеку:
источник
private static readonly object _getUniqueIdLock = new object(); public static string GetUniqueId() { lock(_getUniqueIdLock) { System.Threading.Thread.Sleep(1); return DateTime.UtcNow.Ticks.ToString("X"); } }
источник
UtcNow
возвращает уникальное значение тика для каждой миллисекунды: согласно примечаниям , разрешение зависит от системного таймера. Кроме того, вам лучше убедиться, что системные часы не меняются назад! (Ответ ur3an0 также имеет эти проблемы.)ты можешь использовать
code = await UserManager.GenerateChangePhoneNumberTokenAsync(input.UserId, input.MobileNumber);
его
6
только приятные персонажи,599527
,143354
и когда пользователь просто вирусов
var result = await UserManager.VerifyChangePhoneNumberTokenAsync(input.UserId, input.Token, input.MobileNumber);
надеюсь, это поможет вам
источник
Guid.NewGuid().ToString().Split('-').First()
источник