НейроАгент

Генерация случайных чисел в C# - Полное руководство

Узнайте, как генерировать случайные числа в C# с использованием класса Random, RandomNumberGenerator и продвинутых техник. Полное руководство с примерами и лучшими практиками.

Вопрос

Как сгенерировать случайное целое число в C#?

НейроАгент

Генерация случайных целых чисел в C#

В C# можно генерировать случайные целые числа с помощью нескольких подходов, включая класс Random для базовых нужд, RandomNumberGenerator для криптографической безопасности и более новое свойство Random.Shared в современных версиях .NET. Наиболее распространенным методом является Random.Next(), который предоставляет несколько перегрузок для генерации чисел в определенных диапазонах или с разными распределениями.

Содержание

Базовая генерация случайных целых чисел

Класс Random в пространстве имен System является самым простым способом генерации случайных целых чисел в C#. Вот ключевые методы:

Создание экземпляра Random

csharp
// Создание нового экземпляра Random
Random random = new Random();

// Для .NET 6 и новее, используйте общий экземпляр
Random.Shared.Next();

Распространенные методы Random.Next()

Класс Random предоставляет несколько перегрузок метода Next():

  1. Генерация неотрицательного случайного целого числа:
csharp
int number = random.Next(); // Возвращает от 0 до Int32.MaxValue
  1. Генерация случайного целого числа в указанном диапазоне:
csharp
int number = random.Next(10); // Возвращает от 0 до 9 (верхняя граница исключена)
int number = random.Next(1, 10); // Возвращает от 1 до 9
  1. Генерация случайного 64-битного целого числа (.NET 6+):
csharp
long number = Random.Shared.NextInt64(); // Возвращает от 0 до Int64.MaxValue
long number = Random.Shared.NextInt64(1, 100); // Возвращает от 1 до 99

Полный пример

csharp
using System;

class Program
{
    static void Main()
    {
        Random random = new Random();
        
        // Генерация различных случайных чисел
        Console.WriteLine($"Случайное неотрицательное: {random.Next()}");
        Console.WriteLine($"Случайное 0-9: {random.Next(10)}");
        Console.WriteLine($"Случайное 1-10: {random.Next(1, 11)}");
        
        // Возможности .NET 6+
        if (Environment.Version.Major >= 6)
        {
            Console.WriteLine($"Случайное long: {Random.Shared.NextInt64()}");
            Console.WriteLine($"Случайное long 1-100: {Random.Shared.NextInt64(1, 101)}");
        }
    }
}

Криптографически безопасные случайные числа

Когда вам нужны криптографически безопасные случайные целые числа (для токенов безопасности, паролей или криптографических операций), используйте класс RandomNumberGenerator:

Использование RandomNumberGenerator

csharp
using System.Security.Cryptography;

// Генерация случайного байта
byte[] randomBytes = new byte[1];
RandomNumberGenerator.Fill(randomBytes);
int randomByteValue = randomBytes[0];

// Генерация случайного целого числа в диапазоне
int min = 1;
int max = 100;
int randomNumber = RandomNumberGenerator.GetInt32(min, max);

Полный пример безопасности

csharp
using System;
using System.Security.Cryptography;

class SecurityExample
{
    public static int GenerateSecureRandomNumber(int min, int max)
    {
        if (min > max)
            throw new ArgumentException("Минимальное значение должно быть меньше или равно максимальному");
        
        return RandomNumberGenerator.GetInt32(min, max);
    }
    
    public static byte[] GenerateSecureRandomBytes(int length)
    {
        byte[] bytes = new byte[length];
        RandomNumberGenerator.Fill(bytes);
        return bytes;
    }
}

Продвинутые техники генерации случайных чисел

Взвешенный случайный выбор

csharp
using System;
using System.Collections.Generic;

class WeightedRandom
{
    public static T ChooseWeightedRandom<T>(Dictionary<T, int> weightedItems)
    {
        if (weightedItems == null || weightedItems.Count == 0)
            throw new ArgumentException("Словарь не может быть null или пустым");
        
        int totalWeight = weightedItems.Values.Sum();
        int randomWeight = new Random().Next(totalWeight);
        
        int currentWeight = 0;
        foreach (var item in weightedItems)
        {
            currentWeight += item.Value;
            if (randomWeight < currentWeight)
                return item.Key;
        }
        
        return weightedItems.Keys.Last();
    }
}

Случайные числа с гауссовским (нормальным) распределением

csharp
using System;
using System.Collections.Generic;

class GaussianRandom
{
    private readonly Random random = new Random();
    private readonly List<double> buffer = new List<double>();
    
    public double NextGaussian(double mean = 0, double standardDeviation = 1)
    {
        if (buffer.Count > 0)
        {
            double value = buffer[0];
            buffer.RemoveAt(0);
            return value * standardDeviation + mean;
        }
        
        // Преобразование Box-Muller
        double u1 = 1.0 - random.NextDouble();
        double u2 = 1.0 - random.NextDouble();
        double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2);
        
        buffer.Add(randStdNormal);
        return randStdNormal * standardDeviation + mean;
    }
}

Алгоритм случайного перемешивания

csharp
using System;
using System.Collections.Generic;

class RandomExtensions
{
    private static readonly Random random = new Random();
    
    public static void Shuffle<T>(this IList<T> list)
    {
        int n = list.Count;
        while (n > 1)
        {
            n--;
            int k = random.Next(n + 1);
            T value = list[k];
            list[k] = list[n];
            list[n] = value;
        }
    }
}

Лучшие практики и распространенные ошибки

Распространенные ошибки, которых следует избегать

  1. Создание слишком многих экземпляров Random:
csharp
// ПЛОХО: Создание нескольких экземпляров в цикле
for (int i = 0; i < 100; i++)
{
    Random random = new Random(); // Плохая производительность и предсказуемые результаты
    Console.WriteLine(random.Next(10));
}

// ХОРОШО: Повторное использование одного экземпляра
Random random = new Random();
for (int i = 0; i < 100; i++)
{
    Console.WriteLine(random.Next(10));
}
  1. Использование Random для целей безопасности:
csharp
// ПЛОХО: Random не является криптографически безопасным
int securityToken = new Random().Next(1000, 9999);

// ХОРОШО: Используйте RandomNumberGenerator для безопасности
int secureToken = RandomNumberGenerator.GetInt32(1000, 10000);
  1. Игнорирование потокобезопасности:
csharp
// ПЛОХО: Не потокобезопасно
Random random = new Random();
Parallel.For(0, 100, i => 
{
    Console.WriteLine(random.Next(10)); // Может вызывать исключения или давать предсказуемые результаты
});

// ХОРОШО: Потокобезопасный подход
Random random = new Random();
Parallel.For(0, 100, i => 
{
    lock (random)
    {
        Console.WriteLine(random.Next(10));
    }
});

Лучшие практики

  1. Выбор начального значения (seed): Позвольте .NET выбрать начальное значение автоматически, если вам не нужны воспроизводимые результаты
  2. Повторное использование экземпляра: Создавайте один экземпляр Random и используйте его повторно
  3. Знание версии: Используйте Random.Shared в .NET 6+ для лучшей производительности
  4. Проверка диапазона: Всегда проверяйте параметры min/max
  5. Потокобезопасность: Используйте блокировки или потоковое хранилище при необходимости

Рассмотрения производительности

Сравнение производительности

Вот сравнение различных методов генерации случайных чисел:

Метод Операций в секунду Потокобезопасен Криптографический
Random.Next() ~50M Нет Нет
Random.Shared.Next() ~75M Да Нет
RandomNumberGenerator.GetInt32() ~500K Да Да

Советы по оптимизации производительности

  1. Используйте Random.Shared в .NET 6+ для лучшей производительности и потокобезопасности
  2. Кэшируйте экземпляры Random, когда это возможно
  3. Рассмотрите использование массивов при генерации нескольких случайных чисел
  4. Избегайте создания экземпляров Random в tight loops
csharp
// Оптимизированная генерация пакетов
public static int[] GenerateRandomArray(int count, int min, int max)
{
    int[] result = new int[count];
    Random random = Random.Shared;
    
    for (int i = 0; i < count; i++)
    {
        result[i] = random.Next(min, max);
    }
    
    return result;
}

Эффективность использования памяти

Для大规模 генерации случайных чисел рассмотрите использование Span<T> и Random.Shared:

csharp
public static void FillRandom(Span<int> buffer, int min, int max)
{
    Random random = Random.Shared;
    for (int i = 0; i < buffer.Length; i++)
    {
        buffer[i] = random.Next(min, max);
    }
}

Заключение

Генерация случайных целых чисел в C# может быть выполнена с помощью нескольких подходов в зависимости от ваших конкретных потребностей. Для большинства приложений класс Random предоставляет простую и эффективную генерацию случайных чисел, в то время как RandomNumberGenerator следует использовать для операций, чувствительных к безопасности. Современные разработчики .NET должны использовать Random.Shared для лучшей производительности и потокобезопасности.

Ключевые выводы:

  • Используйте Random.Next() для базовой генерации случайных чисел
  • Предпочитайте Random.Shared в .NET 6+ для лучшей производительности
  • Всегда используйте RandomNumberGenerator для криптографических целей
  • Избегайте создания нескольких экземпляров Random, особенно в циклах
  • Учитывайте потокобезопасность при работе со случайными числами в многопоточных приложениях

Для более сложных сценариев изучите взвешенный случайный выбор, генерацию с гауссовским распределением и пользовательские случайные алгоритмы для удовлетворения конкретных математических или статистических требований в ваших приложениях.