2011-02-08 6 views
24

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

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

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

ответ

31

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

+1

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

+1

@ Davy8 - это очень верно - практически во всех моих приложениях мне тоже не нужно семя, но «Random» по-прежнему покрывает эту функциональность. – BrokenGlass

+0

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

17

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

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

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

У меня есть article which covers some of this, который может пригодиться вам.

+1

+1 для безопасности потоков. Я иногда ошибочно делаю предположение, что встроенные классы являются потокобезопасными, если не указано иначе, когда они фактически не являются потокобезопасными, если только они не заявлены. – Davy8

+1

Ваша статья очень хорошая, спасибо –

4

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

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

2

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

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

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

[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

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

Смежные вопросы