每次调用构造函数时,如何使C#随机数生成器更改?

时间:2012-01-20 22:46:02

标签: c# random static constructor

我有两个班,一个是教师班,一个是班级班。在我的程序中,我创建了一个包含10个Teacher对象的数组,每个Teacher对象中有一个包含10个Student对象的数组。每个Student对象还有一个整数数组作为成员变量,当每个Student被实例化时,它自己的整数数组都用随机数生成器中的数字填充。我的程序是这样的:

  • 创建一个类型为Teacher的数组,大小为10
  • 然后用10个实际教师对象填充数组
  • 每个Teacher对象包含一个大小为10的Student对象数组作为成员变量
  • 每个Teacher对象中的Student数组都填充了实际的Student对象
  • 每个学生对象都有一个整数数组,在学生对象构造函数中填充了随机数。

以下是我遇到的问题:似乎每次为每个教师创建10个Student对象时,即使我调用.Next()函数,Student对象构造函数中的随机数生成器也不会重置或更改直到为下一个Teacher对象创建下一组10个Student对象。我想要的是10个教师对象,每个对象都有自己的学生对象,这些对象有自己的整数数组,里面填充了随机生成的数字。

任何帮助将不胜感激!在我的最后一个问题中,我遇到了构造函数的这种问题,这是一个问题是否是静态的,我不确定这次是什么情况。如果我对任何事情都不够清楚,请问我问题!!

更新**所以看完MSDN之后,我在他们的示例代码中找到了“Thread.Sleep(2000)”并将其粘贴到我的学生构造函数中,只是为了看看它做了什么。它似乎已经解决了问题,虽然我的程序现在运行得慢很多,是否有一个最小的睡眠值要等到Random.Next()使用来自时钟的新种子,即使我确实解决了问题,是否有更好的方法吗?我的随机数生成器已经是Student的静态成员变量。

3 个答案:

答案 0 :(得分:5)

如果在短时间内使用默认构造函数Random初始化多个Random()实例,那么您可能会遇到相同的种子值(这取决于时间)因此,每次都产生相同的随机序列。

您可以通过初始化单个静态Random实例并在所有Student实例之间共享来解决此问题。只要您不是多线程,这是非常安全的。

public class Student
{
    private static readonly Random random = new Random();        
}

Random()构造函数的MSDN页面:

  

默认种子值源自系统时钟并具有有限的分辨率。因此,通过调用默认构造函数紧密连续创建的不同Random对象将具有相同的默认种子值,因此将生成相同的随机数集。使用单个Random对象生成所有随机数可以避免此问题。您还可以通过修改系统时钟返回的种子值,然后将此新种子值显式提供给Random(Int32)构造函数来解决此问题。有关更多信息,请参阅Random(Int32)构造函数。

编辑:虽然您声明您的随机数生成器已经是静态成员,但如果您在每次Student初始化期间重复(冗余地)实例化它,那么这仍然是不够的。以下代码仍不正确

public class Student
{
    private static Random random;

    private int[] numbers;

    public Student()
    {
        random = new Random();
        numbers = new int[10];
        for (int i = 0; i < 10; ++i)
            numbers[i] = random.Next();
    }
}

您需要将其替换为仅实例化Random一次的版本,如下所示:

public class Student
{
    private static readonly Random random = new Random();

    private int[] numbers;

    public Student()
    {
        numbers = new int[10];
        for (int i = 0; i < 10; ++i)
            numbers[i] = random.Next();
    }
}

答案 1 :(得分:5)

Random的常见缺陷是每次需要随机值时都要创建一个新实例。

for (int i = 0; i < 1000; i++) {
   var random = new Random();
   list.Add(random.Next());
}

这不能按预期工作,因为Random使用实际时间来创建第一个随机值。但是,时钟的分辨率有限。可能是几个连续的迭代返回相同的时间,因此返回相同的(伪)随机值!

解决方案是只创建一次random

var random = new Random();
for (int i = 0; i < 1000; i++) {
   list.Add(random.Next());
}

您也可以将random声明为静态类成员

public static readonly Random RandomGenerator = new Random();

答案 2 :(得分:1)

随机数生成器使用系统时间作为种子。我想知道你是否可能在系统有时间进入下一个增量之前声明一个新的发生器并调用它。处理器周期实际上通常比系统时钟更快。你能发一个代码示例吗?

我建议将静态生成器声明为类属性或其他可访问的属性,将其实例化为final。这将保证您不会用另一个覆盖发电机。