Почему класс System.Random не является статичным? - PullRequest
24 голосов
/ 08 февраля 2011

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

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

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

Ответы [ 5 ]

31 голосов
/ 08 февраля 2011

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

17 голосов
/ 08 февраля 2011

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

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

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

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

4 голосов
/ 08 февраля 2011

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

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

2 голосов
/ 08 февраля 2011

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

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

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

[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; }
}
1 голос
/ 15 ноября 2013

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

...