День девятьсот тридцать первый. #ЗаметкиНаПолях
Генерация случайных чисел в .NET
Уже давно мы можем использовать класс
Random для генерации «случайных» чисел:
var randomGenerator = new Random();
randomGenerator.Next(1, 1000000);
Этот код выдаст случайное число от 1 до 1 миллиона.
Однако Random в C# использует значение посева, которое затем используется в алгоритме генерации чисел. Передав одно и то же значение посева, вы получите ту же последовательность случайных чисел. Например:
var randomGenerator = new Random(123);
var random1 = randomGenerator.Next(1, 1000000);
randomGenerator = new Random(123);
var random2 = randomGenerator.Next(1, 1000000);
Console.WriteLine(random1 == random2); //true
И вы, вероятно, скажете: «
Тогда просто не передавайте ему то же самое число посева». На самом деле в класс Random всегда передаётся посев, нравится вам это или нет. Когда конструктору
Random не передан посев, в .NET Framework он использует миллисекундную часть времени в качестве посева, а в .NET Core/.NET5+ используется генератор псевдослучайных чисел.
Поэтому в .NET Framework, согласно документации:
В большинстве систем Windows случайные объекты, созданные с интервалом в 15 миллисекунд, скорее всего, будут иметь идентичные начальные значения.
Но это происходит только в том случае, если вы создаёте генератор случайных чисел несколько раз. Если вместо этого вы каждый раз используете один и тот же экземпляр
Random, то такой коллизии не возникнет:
var randomGenerator = new Random();
var random1 = randomGenerator.Next(1, 1000000);
//другое число из того же экземпляра Random
var random2 = randomGenerator.Next(1, 1000000);
Класс
Random в .NET хорош, но не «по-настоящему случаен». Если вы используете один и тот же экземпляр
Random в своем коде для генерации нескольких случайных чисел, скорее всего, у вас всё будет хорошо, но это не идеальный вариант. Что же мы можем использовать, когда нужно больше случайности?
Использование класса RandomNumberGenerator
Этот класс фактически присутствует во всех версиях .NET, но в .NET Core 3+ в нём появились вспомогательные методы, помогающие вам оперировать не случайными байтами, а сразу числами:
var random = RandomNumberGenerator.GetInt32(1, 1000000);
Этот генератор случайных чисел построен на основе API криптографии, чтобы быть максимально случайным. Таким образом, если вам нужно что-то по-настоящему случайное (например, соль для пароля), вам следует использовать
RandomNumberGenerator, а не класс
Random.
Зачем же тогда вообще использовать Random?
Одной из причин может быть скорость. Вызов метода
Next класса
Random гораздо быстрее, чем использование
RandomNumberGenerator.GetInt32. Поэтому, если вам не критична «настоящая случайность», но требуется создать много псевдослучайных чисел, лучшим вариантом будет создание объекта
Random и генерация серии чисел через последовательный вызов метода
Next на этом объекте.
Источник: https://dotnetcoretutorials.com/2021/08/10/generating-random-numbers-in-net/