我正在尝试在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);
}
}
答案 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)提供这个新的种子值 构造函数。