使用System.Random
类时,必须创建它的实例。为什么不是static
?因为如果我想要一个0到9之间的随机数,我可以使用静态方法,System.Random.Next(int, int)
:
int ourRandomNumber = Random.Next(0,9);
那么为什么班级不仅仅是static
?
答案 0 :(得分:31)
如果它是静态的,您将无法使用不同的种子 - Random实例会跟踪该状态。
默认情况下,Random使用当前时间作为种子,但重新使用特定种子(即new Random(42)
)可以准确地重复随机数序列 - 对于同一种子,它们将始终相同。这方面在某些应用中非常重要。例如,Minecraft。
答案 1 :(得分:17)
Random
不是线程安全的。每个线程有一个Random
实例,但你不应该同时使用多个线程中的一个实例。因此,您不能在静态变量中只有一个Random
实例,而是使用静态方法中的实例。
此外,如BrokenGlass
所述,将其设为静态会删除提供特定种子的机会。
当然,当你不需要来指定一个种子时,创建一个处理线程安全的静态方法并不会太难,但仍然保留实例方法的时候你想使用一个特定的实例。就个人而言,我认为将“随机数源”视为在适当时注入的依赖是恰当的。
我有一个article which covers some of this,您可能会发现它很有用。
答案 2 :(得分:4)
有时你想要“随机的东西”,而你并不关心如何得到随机值。有一个静态的方法可以工作。
但是,有时您希望能够重复获得相同的随机序列。为此,您使用带有种子值的构造函数的重载,在这种情况下,您不希望任何其他使用随机数的代码使用 序列中的一个数字。在这种情况下,您肯定需要类
的实例答案 3 :(得分:2)
具有可重复的“随机”序列在测试场景中非常有用。
例如,您可以在测试游戏引擎时使用它来确保AI正确地选择目标或路径 - 即使它具有随机路径评估。
这是一个非常简单的例子。无论你运行多少次测试,当给定相同的基本随机数发生器时,它总是会选择相同的三张卡。 这可以用于确保使用的随机数生成器是所提供的随机数生成器。并且,由于某种原因,如果在不改变测试的情况下引入新的随机数发生器,则测试将失败。
[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; }
}
答案 4 :(得分:1)
通常当一个人正在调试一个程序时,在执行了更多步骤之前,一步中的不正确行为可能没有明显的症状,到那时原始原因可能已被遮挡。在这种情况下,能够从头开始重新启动例如发生故障的程序是非常有用的。步骤1,000,000并让它完全按照第一次运行第一个999,990左右的步骤,然后暂停让程序员检查其状态。如果程序生成真正的“随机”数字,则无法进行此类调试,但如果它使用伪随机生成器,则可以在第二次运行时使用与第一次运行时使用的相同种子重新加载。 / p>