Согласно вашему обновлению2, вы правы в Guids, и это предсказуемо, даже если msdn ссылается на это. Вот метод, который использует crptographicly сильный генератор случайных чисел для создания идентификатора.
static long counter; //store and load the counter from persistent storage every time the program loads or closes.
public static string CreateRandomString(int length)
{
long count = System.Threading.Interlocked.Increment(ref counter);
int PasswordLength = length;
String _allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ23456789";
Byte[] randomBytes = new Byte[PasswordLength];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(randomBytes);
char[] chars = new char[PasswordLength];
int allowedCharCount = _allowedChars.Length;
for (int i = 0; i < PasswordLength; i++)
{
while(randomBytes[i] > byte.MaxValue - (byte.MaxValue % allowedCharCount))
{
byte[] tmp = new byte[1];
rng.GetBytes(tmp);
randomBytes[i] = tmp[0];
}
chars[i] = _allowedChars[(int)randomBytes[i] % allowedCharCount];
}
byte[] buf = new byte[8];
buf[0] = (byte) count;
buf[1] = (byte) (count >> 8);
buf[2] = (byte) (count >> 16);
buf[3] = (byte) (count >> 24);
buf[4] = (byte) (count >> 32);
buf[5] = (byte) (count >> 40);
buf[6] = (byte) (count >> 48);
buf[7] = (byte) (count >> 56);
return Convert.ToBase64String(buf) + new string(chars);
}
РЕДАКТИРОВАТЬ Я знаю, что есть некоторое смещение, потому что allowedCharCount
не делится поровну на 255, вы можете избавиться от смещения, выбрасывая и получая новое случайное число, если оно приземлится в ничейной стране остаток.
EDIT2 - это не гарантированно уникально, вы можете хранить статический 64-битный (или выше, если необходимо) монотонный счетчик, кодировать его в base46 и иметь первые 4-5 символов идентификатора.
ОБНОВЛЕНИЕ - теперь гарантированно будет уникальным
ОБНОВЛЕНИЕ 2: алгоритм теперь медленнее, но убрал смещение.
РЕДАКТИРОВАТЬ: Я только что выполнил тест, я хотел, чтобы вы знали, что ToBase64String может возвращать не алфавитно-цифровые символы (например, 1 кодирует "AQAAAAAAAAA="
), просто чтобы вы знали.
Новая версия:
Начиная с Ответ Мэтта Дотсона на этой странице, если вы не очень беспокоитесь о пространстве клавиш, вы можете сделать это таким образом, и он будет работать намного быстрее.
public static string CreateRandomString(int length)
{
length -= 12; //12 digits are the counter
if (length <= 0)
throw new ArgumentOutOfRangeException("length");
long count = System.Threading.Interlocked.Increment(ref counter);
Byte[] randomBytes = new Byte[length * 3 / 4];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(randomBytes);
byte[] buf = new byte[8];
buf[0] = (byte)count;
buf[1] = (byte)(count >> 8);
buf[2] = (byte)(count >> 16);
buf[3] = (byte)(count >> 24);
buf[4] = (byte)(count >> 32);
buf[5] = (byte)(count >> 40);
buf[6] = (byte)(count >> 48);
buf[7] = (byte)(count >> 56);
return Convert.ToBase64String(buf) + Convert.ToBase64String(randomBytes);
}