C# - 生成随机生成的字符列表的问题

时间:2014-06-12 06:53:25

标签: c# winforms random

我正在尝试在WinForms应用程序中创建随机生成的密码列表。在下面的代码中,如果我在Console.WriteLine(“”)上放置一个断点; line,使用指定的chars生成指定数量的不同密码。如果我没有在这里放置断点,则返回的所有密码都是相同的。

我知道我可能会遗漏一些非常简单但却看不到的东西。没有线程,此时在UI线程上发生这种情况。我已经使用测试控制台和WinForms应用程序进行了一些测试,结果相同 - 所以我认为这不是WinForms相关的问题。有什么想法吗?

class PasswordGenerator
{
    public List<String> GenerateLowSecurityPasswords(int numOfChars, int numOfPasswords)
    {
        List<String> passwords = new List<String>();

        for (int i = 0; i < numOfPasswords; i++)
        {
            passwords.Add(this.GenerateLowSecurityPassword(numOfChars));
            Console.WriteLine("");
        }

        return passwords;
    }

    private String GenerateLowSecurityPassword(int numOfChars)
    {
        Random rnd = new Random();

        char[] passwd = new char[numOfChars];
        string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789";

        for (int i = 0; i < numOfChars; i++)
        {
            passwd[i] = allowedChars[rnd.Next(0, allowedChars.Length)];
        }

        return new String(passwd);
    }
}

2 个答案:

答案 0 :(得分:1)

我只对new Random()的位置进行了微小的更改,因为当您在每个循环中创建一个新的时,您将获得您遇到的行为。

如果您对为什么要为每个密码创建一个新的Random()感到好奇,我建议您阅读:http://csharpindepth.com/Articles/Chapter12/Random.aspx

简化,它与您的计算机无法生成随机数有关,它只能生成具有预定算法的数字(这对我们来说似乎是随机的)。因此,如果您使用相同的种子创建两个单独的Random()实例,则它们将生成相同的数字,因为它们遵循相同的算法

在下面编辑的代码中,我添加了DateTime.Now.Millisecond作为算法的种子或起点。这只是为每次运行时为算法提供一个新的起点。

https://dotnetfiddle.net/AFH0Bz

public class Program
{
    public static void Main()
    {
        var pwds = GenerateLowSecurityPasswords(4, 10);
        foreach (var p in pwds)
            Console.WriteLine(p);
    }

    public static List<String> GenerateLowSecurityPasswords(int numOfChars, int numOfPasswords)
    {
        // Moved the creating of the random object here and added a random seed to it so that 
        //it will generate different passwords instead of the same for all
        Random rnd = new Random(DateTime.Now.Millisecond);

        List<String> passwords = new List<String>();
        for (int i = 0; i < numOfPasswords; i++)
        {
              passwords.Add(GenerateLowSecurityPassword(numOfChars, rnd));      
        }

        return passwords;
    }

    private static String GenerateLowSecurityPassword(int numOfChars, Random rnd)
    {

        char[] passwd = new char[numOfChars];
        string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789";
        for (int i = 0; i < numOfChars; i++)
        {
            passwd[i] = allowedChars[rnd.Next(0, allowedChars.Length)];
        }

        return new String(passwd);
    }
}

答案 1 :(得分:1)

尝试在构造函数中初始化Random对象。

class PasswordGenerator
{
    Random rnd;
    public PasswordGenerator()
    {
       rnd = new Random();
    }

    ...
}

原因是用于初始化Random的时钟的有限分辨率。 Random的后续初始化将在随机序列中获得相同的起始位置。当重用相同的Random时,总是生成随机序列中的下一个值。

MSDN备注:

  

默认种子值是从系统时钟派生的,并且是有限的   解析度。 因此,创建了不同的Random对象   通过调用默认构造函数来关闭连续   相同的默认种子值,因此,将产生相同的   随机数集。使用单个可以避免此问题   随机对象生成所有随机数。您也可以解决   它通过修改系统时钟返回的种子值然后   明确地向Random(Int32)提供这个新的种子值   构造函数。