Как сгенерировать случайное целое число в C#?
Проблема с генерацией случайных чисел в C#
Вы столкнулись с классической ошибкой начинающих разработчиков. Проблема в том, что вы создаёте новый экземпляр Random каждый раз, когда нужно получить случайное число. Random использует системное время как начальное зерно (seed). Если вы создаёте несколько объектов Random за короткий промежуток времени, они получают одинаковое зерно и генерируют одинаковую последовательность чисел.
Правильное решение: один экземпляр Random
Создайте один статический экземпляр Random и используйте его повторно. Вот правильный подход:
class Program
{
private static readonly Random random = new Random();
static void Main()
{
for (int i = 0; i < 5; i++)
{
int secretNumber = random.Next(1, 101);
Console.WriteLine($"Попытка {i + 1}: {secretNumber}");
}
}
}
Основные методы Random для целых чисел
- Random.Next() — возвращает неотрицательное случайное целое число (0 до int.MaxValue - 1).
- Random.Next(int maxValue) — возвращает число от 0 (включительно) до maxValue (исключительно). Пример:
random.Next(10)даёт числа 0-9. - Random.Next(int minValue, int maxValue) — возвращает число от minValue (включительно) до maxValue (исключительно). Пример:
random.Next(1, 101)даёт числа 1-100.
Безопасность для многопоточности
Если ваше приложение использует несколько потоков, статический Random может вызвать проблемы (он не потокобезопасен). Используйте ThreadLocal<Random> или блокировку:
private static readonly ThreadLocal<Random> threadRandom =
new ThreadLocal<Random>(() => new Random(Environment.TickCount));
public static int GenerateRandomInt(int min, int max)
{
return threadRandom.Value.Next(min, max);
}
Криптостойкие случайные числа
Для паролей, токенов или других задач, требующих безопасности, используйте System.Security.Cryptography.RandomNumberGenerator:
using System.Security.Cryptography;
public static int GetSecureRandomInt(int min, int max)
{
using (var rng = RandomNumberGenerator.Create())
{
byte[] bytes = new byte[4];
rng.GetBytes(bytes);
uint value = BitConverter.ToUInt32(bytes, 0);
return (int)(min + (value % (max - min)));
}
}
Почему ваш код не работал?
Если вы создавали Random random = new Random(); внутри цикла или при каждом вызове метода, все экземпляры получали одно и то же зерно (временную метку с одинаковым значением). Поэтому числа повторялись. Запомните правило: один объект Random на всё приложение (или на поток).
Полный пример для вашей игры
class GuessGame
{
private static readonly Random random = new Random();
static void Main()
{
int secretNumber = random.Next(1, 101);
Console.WriteLine("Угадай число от 1 до 100!");
while (true)
{
string input = Console.ReadLine();
if (int.TryParse(input, out int guess))
{
if (guess == secretNumber)
{
Console.WriteLine("Правильно!");
break;
}
Console.WriteLine(guess < secretNumber ? "Больше!" : "Меньше!");
}
else
{
Console.WriteLine("Введите целое число!");
}
}
}
}
<<Альтернативный подход: использование Random.Shared
Начиная с .NET 6, появился статический экземпляр Random.Shared, который является потокобезопасным. Это самый простой способ получить случайное число без создания собственного экземпляра:
int secretNumber = Random.Shared.Next(1, 101);
Random.Shared автоматически управляет потоками и не требует ручного создания объектов. Он идеально подходит для большинства задач, включая игры и симуляции.
Когда использовать Random.Shared?
- В однопоточных приложениях — как замена обычному
Random. - В многопоточных приложениях — без дополнительных блокировок.
- Когда нужна простота и минимализм кода.
Однако для криптографических задач всё равно используйте RandomNumberGenerator, так как Random.Shared не является криптостойким.
Пример с Random.Shared
for (int i = 0; i < 5; i++)
{
Console.WriteLine(Random.Shared.Next(1, 101));
}
Этот подход избавляет вас от необходимости объявлять статическое поле Random. Просто используйте Random.Shared в любом месте программы. Обратите внимание: если ваша среда — .NET Framework (до .NET Core 3.0), то Random.Shared недоступен, и придётся использовать классический способ с одним экземпляром.
Ответов пока нет.
Войдите чтобы оставить ответ