为什么这个方法每次都返回相同的随机字符串?

5

我需要创建一段独特的文本来测试另一个项目,因此我创建了一个简单的程序来生成长度为X的随机字符串。

问题在于,如果我调用它一次,我会得到一个随机字符串;如果我再次调用它(例如在for循环中),我将在整个循环执行期间得到相同的字符串。

我觉得它被缓存了,但我不知道.net是否会这样做,我现在感到很困惑。

调用代码:

    StreamWriter SW = new StreamWriter("c:\\test.txt");
    int x = 100;
    while (x >0)
    {
        SW.WriteLine(RandomString(20));
        x--;
    }

这是方法:

private static string RandomString(int Length)
{
    StringBuilder sb = new StringBuilder();
    Random randomNumber = new Random();

    for (int i = 0; i <= Length; ++i)
    {
        int x = randomNumber.Next(65, 122);
        sb.Append(Convert.ToChar(x));
    }
    return sb.ToString();        
}

以下是输出结果:

"VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
..................
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB"

那么,我认为Random.next()总是会返回一个新的随机数,这是怎么回事?


可能是重复的问题:随机数生成器只生成一个随机数 - user456814
6个回答

25

您正在创建时间间隔非常短的Random实例。每个实例都使用系统时钟进行初始化, 由于时钟没有改变,因此您会一遍又一遍地得到相同的随机数序列。

创建一个Random类的单个实例,并重复使用它。

使用using关键字确保在使用完后关闭和释放StreamWriter。如果使用for关键字,则循环的代码更容易识别。

using (StreamWriter SW = new StreamWriter("c:\\test.txt")) {
   Random rnd = new Random();
   for (int x = 100; x > 0; x--) {
      SW.WriteLine(RandomString(rnd, 20));
   }
}
该方法以Random对象作为参数。
此外,使用长度来初始化StringBuilder,以便在循环期间不必重新分配。 在循环中使用<运算符而不是<=,否则您将创建一个比length参数指定的字符串多一个字符长的字符串。
private static string RandomString(Random rnd, int length) {
   StringBuilder sb = new StringBuilder(length);
   for (int i = 0; i < length; i++) {
      int x = rnd.Next(65, 122);
      sb.Append((char)x);
   }
   return sb.ToString();        
}

12
请参考微软开发者网络中随机数构造函数说明中的这部分内容:

默认种子值基于系统时钟获取,有限精度。因此,在相继调用默认构造函数创建的不同 Random 对象中,它们的默认种子值将完全相同,从而生成相同的随机数集。

因此,要么在程序开始时仅调用一次 Random() 构造函数,要么使用 Random(int32) 构造函数并自定义不同的种子值。


4

因为你在每次调用中创建了一个新的随机对象。

只需将randomNumber从方法中移出,并将其作为类成员即可。

private Random randomNumber = new Random();
private static string RandomString(int Length)
{
    StringBuilder sb = new StringBuilder();
    //...
}

所有的软件随机数生成器都是“伪随机”的,它们基于一个(起始)种子生成数字序列。使用相同的种子,它们会产生相同的序列。有时这是有用的。如果你想让你的程序在每次运行时生成相同的序列,你可以使用new Random(0)

编辑:显然,.Net的Random类是自动种子化的,我不知道这一点。所以这是一个时间问题,正如其他人指出的那样。


.NET的Random类不会自动种子吗? - Michael Myers
而且……构造函数使用当前时间戳作为种子,因此每个项都使用相同的种子,因此会随机到完全相同的答案… :) - GalacticCowboy
它确实是这样,但是使用一个时间相关的种子,这个种子似乎不经常改变,可以参考我的答案。 - schnaader
问题不在于自动播种。自动播种是可以的,但是在短时间内创建多个随机对象将意味着它们都具有相同的初始种子。 - Matthew Flaschen
@mmyers,它确实是基于系统时间的,参见@schnaader的回答。 - TygerKrash

3

只需声明一次randomNumber



public class MyClass
{
    private static Random randomNumber = new Random();

    private static string RandomString(int Length)
    {
        StringBuilder sb = new StringBuilder();  

        for (int i = 0; i ... Length; ++i)
        {
        int x = MyClass.randomNumber.Next(65, 122);
        sb.Append(Convert.ToChar(x));
        }
        return sb.ToString();        
    }
}

3

1

由于生成随机数的时间很短,所以随机数的种子都是相同的,实际上每次都会使用相同的种子重新创建随机数生成器,因此 Next() 调用会返回相同的随机值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接