一切福田,不離方寸,從心而覓,感無不通。

Random 类

表示伪随机数生成器,这是一种能够产生满足某些随机性统计要求的数字序列的设备。

若要浏览此类型的.NET Framework 源代码,请参阅 Reference Source

命名空间:   System
程序集:  mscorlib(位于 mscorlib.dll)

 

 

名称 说明
System_CAPS_pubmethod Random()

新实例初始化 Random 类,使用依赖于时间的默认种子值。

System_CAPS_pubmethod Random(Int32)

新实例初始化 Random 类,使用指定的种子值。

名称 说明
System_CAPS_pubmethod Equals(Object)

确定指定的对象是否等于当前对象。(继承自 Object。)

System_CAPS_protmethod Finalize()

在垃圾回收将某一对象回收前允许该对象尝试释放资源并执行其他清理操作。(继承自 Object。)

System_CAPS_pubmethod GetHashCode()

作为默认哈希函数。(继承自 Object。)

System_CAPS_pubmethod GetType()

获取当前实例的 Type(继承自 Object。)

System_CAPS_protmethod MemberwiseClone()

创建当前 Object 的浅表副本。(继承自 Object。)

System_CAPS_pubmethod Next()

返回一个非负随机整数。

System_CAPS_pubmethod Next(Int32)

返回一个小于所指定最大值的非负随机整数。

System_CAPS_pubmethod Next(Int32, Int32)

返回在指定范围内的任意整数。

System_CAPS_pubmethod NextBytes(Byte[])

用随机数填充指定字节数组的元素。

System_CAPS_pubmethod NextDouble()

返回一个大于或等于 0.0 且小于 1.0 的随机浮点数。

System_CAPS_protmethod Sample()

返回一个介于 0.0 和 1.0 之间的随机浮点数。

System_CAPS_pubmethod ToString()

返回表示当前对象的字符串。(继承自 Object。)

 

System_CAPS_note说明
若要查看此类型的.NET Framework 源代码,请参阅 Reference Source 您可以浏览源代码、 下载脱机查看参考资料和调试; 在逐句通过源 (包括修补程序和更新)see instructions.

伪随机数字从一组有限的数字选择以相同的概率。 因为数学算法可用于选择它们,但它们是充分随机实用的角度而言,所选的数字不完全随机的。 当前实现 Random 类根据 Donald E.Knuth 删减随机数生成器算法的修改版本。 有关详细信息,请参阅 D.e。 Knuth。 计算机编程,卷 2 的艺术︰ Seminumerical 算法 Addison-wesley,Reading,MA,第三个版本,1997年。

若要生成加密性极安全的随机数字,如一个适合于创建随机密码,使用 RNGCryptoServiceProvider 类或从派生类 System.Security.Cryptography.RandomNumberGenerator

在本主题中:

实例化的随机数字生成器
避免多个实例化
System.Random 类和线程安全
生成不同类型的随机数字
替换您自己的算法
如何使用到 System.Random…
检索相同的随机值序列
检索唯一的随机值序列
检索指定范围内的整数
检索具有指定位数的数字的整数
检索指定范围中的浮点值
生成随机的布尔值
生成随机的 64 位整数
检索指定范围中的字节
随机从数组或集合检索某个元素
检索的唯一元素从数组或集合

通过提供一个种子值 (起始值的伪随机数字生成算法) 的随机数字生成器实例化为 Random 类构造函数。 您可以显式或隐式提供种子值︰

  • Random(Int32) 构造函数使用您提供一个显式的种子值。
  • Random() 构造函数使用系统时钟提供种子值。 这是实例化的随机数生成器的最常见的方法。

如果同一个种子用于单独 Random 对象,则它们将生成相同的一系列随机数字。 这可以是用于创建测试套件,用于处理随机值,或者用于重播从随机数字派生其数据的游戏。 但请注意, Random 不同版本的.NET Framework 下运行的进程中的对象可能会返回不同的随机数字的序列,即使它们使用相同的种子值实例化。

若要生成的随机数的不同序列,您可以种子值依赖于时间,从而产生不同的系列的每个新实例 Random 参数化 Random(Int32) 构造函数可以采用 Int32 值根据计时周期数以当前时间,而无参数 Random() 构造函数使用系统时钟生成其种子值。 不过,由于时钟具有有限的解决方法,使用无参数构造函数来创建不同 Random 中连续的对象创建生成的随机数的相同序列生成器。 下面的示例阐释了两个 Random 连续实例化的对象生成相同的一系列随机数字。 在大多数 Windows 系统, Random 在另一个 15 毫秒内创建的对象可能会遇到的相同种子值。

若要避免此问题,创建一个 Random 对象而不是多个对象。

初始化两个随机数生成器的紧凑循环中或在短期内创建两个随机数生成器可能会产生相同的随机数字序列。 在大多数情况下,这不是开发人员的意图,会导致性能问题,因为实例化和初始化随机数生成器是一个代价相对较大的过程。

同时以提高性能并避免无意中创建单独的随机数生成器生成相同的数字序列,我们建议您创建一个 Random 对象来生成段时间后,而不是创建新的多个随机数 Random 对象生成一个随机数。

但是, Random 类不是线程安全。 如果调用 Random 方法从多个线程,请按照下一节中讨论的指导原则。

而不是实例化单个 Random 对象时,我们建议您创建一个 Random 实例,以生成应用程序所需的所有随机数字。 但是, Random 对象不是线程安全。 如果您的应用程序调用 Random 从多个线程的方法,您必须使用同步对象来确保只有一个线程可以访问一次的随机数字生成器。 如果您不确保 Random 以线程安全的方式访问对象时,对返回随机数字的方法的调用将返回 0。

下面的示例使用 C# 锁定语句 和 Visual Basic SyncLock 语句 以确保单个随机数生成器的 11 个线程访问以线程安全的方式。 每个线程生成 2 百万个随机数字、 对生成的随机数字的数量进行计数和计算其总和,并执行完后,然后更新所有线程的合计。

该示例通过以下方式将确保线程安全︰

  • ThreadStaticAttribute 属性用来定义用于跟踪生成的随机数字和其总和为每个线程的总数的线程本地变量。
  • 锁 ( lock C# 中的语句和 SyncLock 在 Visual Basic 中的语句) 的总数的计数和所有在所有线程上生成的随机数字的总和的变量的访问权限进行保护。
  • 信号量 ( CountdownEvent 对象) 用于确保主线程阻塞,直到所有其他线程完成执行。
  • 本示例会检查是否为随机数生成器遭到破坏通过确定是否对随机数字生成方法的两个连续调用会返回 0。 如果检测到损坏时,该示例使用 CancellationTokenSource 对象以指示应取消所有线程。
  • 在生成之前每个随机数字,每个线程检查状态 CancellationToken 对象。 如果请求取消时,该示例调用 CancellationToken.ThrowIfCancellationRequested 方法来取消该线程。

下面的示例等同于第一,只不过它使用 Task 对象和 lambda 表达式而不是 Thread 对象。

在以下方面不同的第一个示例︰

  • 变量以跟踪生成的随机数字的数量和每个任务中的其结果相加值仅用于该任务,因此无需使用 ThreadStaticAttribute 属性。
  • 静态 Task.WaitAll 方法用于确保在所有任务都完成之前,不会完成主线程。 有关无需 CountdownEvent 对象。
  • 中出现异常而得出任务取消 Task.WaitAll 方法。 在上例中,它是由每个线程进行处理。

随机数字生成器提供了方法,您可以生成以下类型的随机数字︰

  • 一系列 Byte 值。 通过传递数组初始化为所需的方法以返回到的元素的数目确定字节值的数目 NextBytes 方法。 下面的示例生成 20 个字节。
  • 一个整数。 您可以选择是否希望从 0 到最大值的整数 (Int32.MaxValue – 1) 通过调用 Next() 方法、 0 到通过调用特定的值之间的整数 Next(Int32) 方法或通过调用的值的范围内的整数 Next(Int32, Int32) 方法。 在参数化的重载中, 指定的最大值是独占的;也就是说,生成的实际最大数目是其中一个小于指定值。

    下面的示例调用 Next(Int32, Int32) 方法来生成 10 个随机数字介于-10 和 10 之间。 请注意,该方法的第二个参数指定的由该方法返回的随机值的范围的上限。 换而言之,该方法可返回一个的最大整数少于此值。

  • 单个浮点值介于 0.0 到小于 1.0 通过调用 NextDouble 方法。 该方法返回的随机数的上限为 1,因此它实际的上限是 0.99999999999999978。 下面的示例生成 10 个随机浮点数。
System_CAPS_important重要事项
Next(Int32, Int32) 方法允许您指定返回的随机数的范围。 但是, maxValue 参数,指定的上限范围返回数字,该参数是独占的、 不含值。这意味着方法调用 Next(0, 100) 返回一个值,介于 0 和 99 之间并不介于 0 和 100 之间。

您还可以使用 Random 之类的任务生成的类 随机的布尔值, 、 生成 随机浮点值的范围以外的 0 到 1, 、 生成 64 位的随机整数, ,和 随机从数组或集合中检索的唯一元素 有关这些和其他常见任务,请参阅 如何使用到 System.Random… 部分。

您可以通过继承实现您自己的随机数字生成器 Random 类并提供您随机数字生成算法。 若要提供您自己的算法,必须重写 Sample 方法,实现随机数字生成算法。 您还应该重写 Next(), ,Next(Int32, Int32), ,和 NextBytes 方法以确保它们调用被重写 Sample 方法。 您无需重写 Next(Int32) 和 NextDouble 方法。

有关示例,派生自 Random 类并修改其默认的伪随机数生成器,请参阅 Sample 引用页面。

以下各节讨论并提供了几种可能想要在您的应用程序中使用的随机数的示例代码。

有时您想要在软件测试方案和玩游戏生成相同的随机数字序列。 使用相同的随机数字序列进行测试,可检测到回归测试并确认 bug 已修复。 在游戏中使用相同的随机数字序列可以重播以前的游戏。

您可以通过提供到相同的种子值生成相同的随机数字序列 Random(Int32) 构造函数。 种子值为伪随机数字生成算法提供一个起始值。 下面的示例使用 100100 为任意种子值来实例化 Random 对象,显示 20 个随机浮点值,并且仍然存在的种子值。 然后还原的种子值、 实例化新的随机数字生成器,并显示相同的 20 随机浮点值。 请注意是否在不同版本的.NET Framework 上运行,则可能会产生不同的随机数字序列。

提供不同的种子值的实例 Random 类将导致每个随机数生成器来生成不同的值序列。 可以通过调用显式提供一个种子值 Random(Int32) 构造函数,或隐式调用 Random() 构造函数。 大多数开发人员调用无参数构造函数,使用系统时钟。 下面的示例使用这种方法来实例化两个 Random 实例。 每个实例显示 10 个随机整数的一系列。

但是,由于其有限的解决方法,系统时钟不会检测少于大约 15 毫秒的时间差异。 因此,如果你的代码调用 Random() 要实例化两个重载 Random 中连续,您可能会无意中提供这些对象具有相同的种子值的对象。 若要查看此上一示例中,注释掉 Thread.Sleep 方法调用和编译和重新运行该示例。

若要防止这种情况发生,我们建议您实例化一个 Random 对象而不是多个会话。 但是,由于 Random 不是线程安全的如果您访问,则必须使用一些同步设备 Random 实例从多个线程; 有关详细信息,请参阅 随机的类和线程安全 本主题前面的。 或者,可以使用延迟机制,如 Sleep 方法使用在上一示例中,以确保实例化会相隔超过 15 毫秒。

可以通过调用来检索指定范围内的整数 Next(Int32, Int32) 方法,可以指定您想要返回的随机数生成器的数的上限和较低。 上限是独占的、 不含值。 也就是说,它不包含在由该方法返回的值的范围。 下面的示例使用此方法生成介于-10 和 10 之间的随机整数。 请注意,它指定 11 中,这是一个大于所需的值,该值的 maxValue 方法调用中的参数。

您可以调用 Next(Int32, Int32) 方法来检索具有指定位数的数字的数字。 例如,若要检索具有四位数字 (也就是说,范围为 1000年至 9999 的数字) 的数字,则调用 Next(Int32, Int32) 方法 minValue 当值为 1000年和 maxValue 值为 10000,如以下示例所示。

NextDouble 方法返回随机浮点值,范围从 0 到小于 1。 但是,您通常需要在另一个范围中生成随机值。

如果最小值和最大所需值之间的间隔为 1 时,可以将所需的起始时间间隔和 0 之间的差异添加到返回的数字 NextDouble 方法。 下面的示例这样做是为了生成 10 个随机数字之间-1 和 0。

生成随机浮点数其下限为 0,但上限大于 1 (或者,对于负数,其下限为小于-1,上限为 0),再乘以非零值绑定的随机数字。 下面的示例这样做是为了生成 2000 万个随机浮点数,范围从 0 到 Int64.MaxValue 此外会在显示的方法生成的随机值的分布。

若要生成两个任意值之间的随机浮点数,喜欢 Next(Int32, Int32) 方法不为整数,则使用以下公式︰

下面的示例生成 100 万个随机数字,范围为从 10.0 为 11.0,并显示其分发。

Random 类没有提供生成的方法 Boolean 值。 但是,您可以定义您自己的类或方法来做到这一点。 下面的示例定义一个类, BooleanGenerator, ,具有单个方法 NextBoolean BooleanGenerator 类存储 Random 对象作为一个私有变量。 NextBoolean 方法调用 Random.Next(Int32, Int32) 方法并传递给 Convert.ToBoolean(Int32) 方法。 请注意,使用 2 作为参数来指定随机数的上限。 由于这是排他值,该方法调用将返回 0 或 1。

而不是创建一个单独的类生成随机 Boolean 值,则可能只需定义一种方法。 在这种情况下,但是, Random 对象应被定义为类级别变量,以避免实例化一个新 Random 中每个方法调用的实例。 在 Visual Basic 中,Random 实例可以定义为 静态 变量中 NextBoolean 方法。 下面的示例提供了一个实现。

重载 Next 方法返回 32 位整数。 但是,在某些情况下,您可能想要使用 64 位整数。 你可以按如下所示进行操作:

  1. 调用 NextDouble 方法来检索双精度浮点值的点。
  2. 将该值相乘, Int64.MaxValue

下面的示例使用该技术来生成 2000 万个随机长整数,并在 10 个相等组中对其进行分类。 然后通过计算从 0 到每个组中的数量计算分布的随机数字 Int64.MaxValue 如示例输出所示,数字增加或减少均匀地分布在执行一个长整型的范围。

使用位操作的替代技术不生成真正的随机数字。 此方法调用 Next() 来生成两个整数,左移一个由 32 位 Or 它们组合在一起。 此方法具有两个限制︰

  1. 由于第 31 位是符号位,第 31 位所产生的长整数的中的值始终为 0。 这可以通过生成随机 0 或 1,左移 31 个位和 or 操作来解决其与原始随机的长整型。
  2. 更严重,因为返回的值的概率 Next() 将为 0,则将是随机数字,如果有几个 0x0 0x00000000FFFFFFFF 的范围。

重载 Next 方法允许您指定的随机数字,范围,但 NextBytes 方法却没有。 下面的示例实现 NextBytes 方法,可使您可以指定返回的字节范围。 它定义了 Random2 派生自的类 Random 并重载其 NextBytes 方法。

NextBytes(Byte[], Byte, Byte) 方法包装调用 Next(Int32, Int32) 方法,并指定的最小值和一个大于最大值 (在这种情况下,0 和 101),我们希望返回的字节数组中。 因为我们可以确保返回的整数值 Next 方法的范围内有 Byte 数据类型,我们可以安全地将它们强制转换 (在 C# 中) 或将它们 (在 Visual Basic 中) 从整数转换为字节。

随机数字经常充当要从数组或集合中检索值的索引。 若要检索随机索引值,可以调用 Next(Int32, Int32) 方法,并使用的下限数组的值作为其 minValue 参数和一个大于上限的数组的值作为其 maxValue 参数。 对于从零开始的数组,该属性等同于其 Length 属性,或一个返回的值大于 Array.GetUpperBound 方法。 下面的示例随机从一个城市数组检索在美国城市的名称。

随机数字生成器始终能够返回重复的值。 当的编号的范围变得更小或生成的值的数目越大,就会增加重复项的概率。 如果随机值必须是唯一的其他号码会生成来弥补重复项,从而越来越多地影响性能。

有多种方法来处理此情况。 一个常见的解决方案是创建一个包含随机浮点数的并行数组和数组或集合,其中包含要检索的值。 创建第一个数组,次用随机数填充第二个数组和 Array.Sort(Array, Array) 方法用于按使用并行数组中的值进行排序的第一个数组。

例如,如果要开发一个纸牌游戏,您想要确保每个卡使用仅一次。 而不是生成随机数字,以检索的卡和跟踪是否已处理该卡,您可以创建可用于对此演示文稿进行排序的随机数字的并行数组。 排序此演示文稿,一旦您的应用程序可以维护的指针来指示该发牌叠上的下一步卡的索引。

下面的示例阐释了这种方法。 它定义了 Card 类表示游戏卡和 Dealer 处理一副牌组成打乱顺序的类。 Dealer 类构造函数填充两个数组︰ deck数组具有类范围,该值表示此演示文稿; 与一个本地中的所有牌 order 数组,其中包含相同数量的元素作为 deck 数组并使用随机生成的填充 Double 值。 Array.Sort(Array, Array) 然后调用方法来排序 deck 中的值基于阵列 order 数组。

调用函数说明:

中的随机数字生成器的实现 Random 类不能保证在.NET framework 的主版本之间将保持不变。 因此,您不应假定同一个种子将导致不同版本的.NET Framework 中的同一个伪随机序列。

继承函数说明:

在.NET Framework 1.0 和 1.1 中,类的一个最小实现派生自 Random 需要重写 Sample 方法来定义使用新的或已修改的算法来生成随机数字。 派生的类无法再依赖于的基类实现 Random.Next(), ,Random.Next(Int32), ,Random.Next(Int32, Int32), ,NextBytes, ,和 NextDouble 方法来调用的派生的类实现 Sample 方法。

在.NET Framework 2.0 及更高版本的行为 Random.Next(), ,Random.Next(Int32, Int32), ,和 NextBytes 方法已更改,以便这些方法不一定是调用的派生的类实现 Sample 方法。 从派生类的结果是, Random ,面向.NET Framework 2.0 和更高版本还应该重写这三种方法。

下面的示例创建一个随机数生成器,并调用其 NextBytes, ,Next, ,和 NextDouble 要生成的不同范围内的随机数字序列的方法。

下面的示例将生成一个随机整数,它使用索引作为从数组中检索一个字符串值。

通用 Windows 平台
自 8 起可用
.NET Framework
自 1.1 起可用
可移植类库
在 可移植 .NET 平台 中受支持
Silverlight
自 2.0 起可用
Windows Phone Silverlight
自 7.0 起可用
Windows Phone
自 8.1 起可用

此类型的所有公共静态(Visual Basic 中的 已共享 在 Visual Basic 中)成员都是线程安全的。不保证所有实例成员都是线程安全的。