为什么System.Random类不是静态的?

使用System.Random类时,必须创建它的实例。 为什么它不是static ? 因为如果我想要一个0到9之间的随机数,我可以使用静态方法 System.Random.Next(int, int)

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

那么为什么class级不是static呢?

如果它是静态的,您将无法使用不同的种子 – Random实例会跟踪该状态。 默认情况下,Random使用当前时间作为种子,但重新使用特定种子(即new Random(42) )允许您准确地重复随机数序列 – 它们对于相同的种子始终是相同的。 这方面在某些应用中非常重要。 例如,Minecraft。

Random不是线程安全的。 每个线程有一个Random实例,但不应同时使用多个线程中的一个实例。 因此,您不能在静态变量中只有一个Random实例,而是使用静态方法中的一个实例。

而且,如BrokenGlass所述,将其设置为静态会消除提供特定种子的机会。

当然,在不需要指定种子的情况下创建处理线程安全性的静态方法并不太难,但是当您想要使用特定实例时仍然保留实例方法。 就个人而言,我觉得将“随机数字来源”视为在适当时注入的依赖是恰当的。

我有一篇文章介绍了其中的一些内容 ,您可能会觉得它很有用。

有时你想要“随机的东西”,而你并不关心随机值是如何得出的。 有一个静态方法可以工作。

但是,有时您希望能够重复获得相同的随机序列。 为此,您使用带有种子值的构造函数的重载,在这种情况下,您不希望任何其他使用随机数的代码使用序列中的一个数字。 在这种情况下,您肯定需要该类的实例

具有可重复的“随机”序列在测试场景中非常有用。

例如,您可以在测试游戏引擎时使用它来确保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 _cards = new List { 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 Cards { get { return _cards; } } public Card PickCard() { return Cards[_randomizer.Next(0, Cards.Count - 1)]; } } public class Card { public int Value { get; set; } } 

通常,当一个人正在调试程序时,在执行了更多步骤之前,一步中的不正确行为可能没有可见的症状,到那时原始原因可能已被遮挡。 在这种情况下,能够从头开始重新启动一个程序,例如步骤1,000,000,并让它完全按照第一次运行第一个999,990左右的步骤,然后暂停让程序员检查它,这非常有用。州。 如果程序生成真正的“随机”数字,则无法进行此类调试,但如果它使用伪随机生成器,则可以在第二次运行时使用与第一次运行时使用的相同种子重新加载。