随机类生成相同的序列

时间:2014-02-22 13:48:03

标签: c# .net random random-sample

我有一个方法,我用它来创建随机字符串,通过创建随机整数并将它们转换为char

public static string GenerateRandomString(int minLength, int maxLength)
        {
            var length = GenerateRandomNumber(minLength, maxLength);

            var builder = new StringBuilder(length);

            var random = new Random((int)DateTime.Now.Ticks);

            for (var i = 0; i < length; i++)
            {
                builder.Append((char) random.Next(255));
            }

            return builder.ToString();
        }

问题在于,当我经常调用此方法时,它会创建相同的值序列,正如文档已经说过的那样:

  

随机数生成从种子值开始。如果相同   种子被重复使用,生成相同的数字序列。一   产生不同序列的方法是制作种子值   时间依赖,从而与每个新系列产生不同的系列   随机实例。

正如您所看到的,我将依赖种子时间,并在每次调用方法时创建Random的新实例。尽管如此,我的测试仍然失败。

[TestMethod]
        public void GenerateRandomStringTest()
        {
            for (var i = 0; i < 100; i++)
            {
                var string1 = Utilitaries.GenerateRandomString(10, 100);
                var string2 = Utilitaries.GenerateRandomString(10, 20);
                if (string1.Contains(string2))
                    throw new InternalTestFailureException("");
            }
        }

如何确保独立于我调用方法的频率,序列将“始终”不同?

3 个答案:

答案 0 :(得分:3)

您的测试失败,因为GenerateRandomString功能过早完成DateTime.Now.Ticks更改。在大多数系统上,它是quantized at either 10 or 15 ms,这足以让现代CPU生成100个随机字符的序列。

在测试中插入一个小延迟应解决问题:

var string1 = Utilitaries.GenerateRandomString(10, 100);
Thread.Sleep(30);
var string2 = Utilitaries.GenerateRandomString(10, 20);

答案 1 :(得分:2)

你实际上和Random的默认构造函数一样。它正在使用Environment.TickCount。查看this MSDN documentationRandom构造函数的示例。它表明在不同Thread.Sleep实例的初始化之间插入Random将产生不同的结果。

如果您真的想获得不同的值,我建议您更改为时间相关的种子值。

答案 2 :(得分:1)

dasblinkenlight已经说明了为什么会这样。

现在你应该这样做来克服这个问题

public static string GenerateRandomString(Random random , int minLength, 
                                                  int maxLength)
{
    var length = GenerateRandomNumber(random , minLength, maxLength);

    var builder = new StringBuilder(length);   

    for (var i = 0; i < length; i++)
         builder.Append((char) random.Next(255));

    return builder.ToString();
}

public void GenerateRandomStringTest()
{
    Random rnd = New Random();
    for (var i = 0; i < 100; i++)
    {
        var string1 = Utilitaries.GenerateRandomString(rnd, 10, 100);
        var string2 = Utilitaries.GenerateRandomString(rnd, 10, 20);
        if (string1.Contains(string2))
            throw new InternalTestFailureException("");
    }
}