Почему класс System.Random не статичен?

Когда вы используете класс System.Random, вы должны сделать его экземпляр. Почему это не static? Поскольку, если я хочу случайное число от 0 до 9, я могу использовать статический метод System.Random.Next(int, int):

int ourRandomNumber = Random.Next(0,9);

Так почему же класс не просто static?

Ответ 1

Вы не смогли бы использовать разные семена, если бы они были статическими - экземпляр Random отслеживает это состояние. По умолчанию Random использует текущее время как семя, но повторное использование определенного семени (т.е. new Random(42)) позволяет точно повторить последовательность случайных чисел - они всегда будут одинаковыми для одного и того же семени. Этот аспект очень важен в некоторых приложениях. Например, Minecraft.

Ответ 2

Random не является потокобезопасным. Хорошо иметь один экземпляр Random для потока, но вы не должны использовать один экземпляр из нескольких потоков одновременно. Таким образом, вы не можете просто иметь один экземпляр Random в статической переменной и использовать его из статического метода.

Кроме того, делая его статическим, можно удалить возможность задать конкретное семя, как указано в BrokenGlass.

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

У меня есть статья которая охватывает некоторые из этих и которые вы можете найти полезными.

Ответ 3

Иногда вы хотите "что-то случайное", и вам не важно, как это случайное значение будет достигнуто. Наличие статического метода для этого может работать.

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

Ответ 4

Наличие повторяемой "случайной" последовательности полезно при тестировании сценариев.

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

Вот очень упрощенный пример. Независимо от того, сколько раз вы запускаете этот тест, он всегда будет выбирать одни и те же три карты при использовании одного и того же базового генератора случайных чисел. Это может быть полезно для обеспечения использования используемого генератора случайных чисел. И по какой-то причине, если новый генератор случайных чисел был введен без изменения теста, то тест завершится неудачей.

[TestMethod]
public void TestRandomPicking()
{
    Random random = new Random(1);
    Deck deck = new Deck(random);


    Assert.AreEqual(3, deck.PickCard().Value);
    Assert.AreEqual(1, deck.PickCard().Value);
    Assert.AreEqual(5, deck.PickCard().Value);

}

public class Deck
{
    public Deck()
    {
        _randomizer = new Random();
    }

    public Deck(Random randomizer)
    {
        _randomizer = randomizer; 
    }

    Random _randomizer;

    private List<Card> _cards = new List<Card>
                                    {
                                        new Card {Value = 1},
                                        new Card {Value = 2},
                                        new Card {Value = 3},
                                        new Card {Value = 4},
                                        new Card {Value = 5},
                                        new Card {Value = 6},
                                        new Card {Value = 7},
                                        new Card {Value = 8},
                                        new Card {Value = 9},
                                        new Card {Value = 10}
                                    };

    private List<Card> Cards { get { return _cards; } }

    public Card PickCard()
    {
        return Cards[_randomizer.Next(0, Cards.Count - 1)];
    }
}

public class Card
{
    public int Value { get; set; }
}

Ответ 5

Часто, когда вы отлаживаете программу, неправильное поведение на одном шаге может не иметь видимых симптомов до тех пор, пока не будет выполнено еще много шагов, и к тому времени исходная причина может быть скрыта. В таких случаях может быть очень полезно иметь возможность перезапускать с нуля программу, которая работает неправильно, например. шаг 1 000 000 и запустить первые 999,990 шагов так же, как и в первый раз, а затем сделать паузу, чтобы позволить программисту проверить его состояние. Такая отладка невозможна, если программа генерирует действительно "случайные" числа, но будет, если вместо нее будет использоваться псевдослучайный генератор, который можно перезагрузить во втором прогоне с тем же семенем, который использовался в первом прогоне.