Class Random无法按预期工作

时间:2015-09-19 04:06:32

标签: vb.net random

该块应该生成一个随机的8个字符的密码。测试时,它在文本框中显示相同的8个字符。如果我一行一行地进行整个迭代,它就能正常工作。如果我逐行进行几个循环,那么让它运行其余的字符将重复。例如,我打破3行然后恢复:abcddddd是我的输出。

是什么导致这种情况发生?

 Private Sub generateBTN_Click(sender As System.Object, e As System.EventArgs) Handles generateBTN.Click
        generateTXT.Clear()
        While generateTXT.Text.Length < 9
            Dim rn As Random = New Random
            Dim num As Integer = rn.Next(33, 126)
            'disallow ();=
            While num = 40 Or num = 41 Or num = 59 Or num = 61
                num = rn.Next(33, 126)
            End While
            Dim numSTR As String = ChrW(num).ToString
            generateTXT.Text = generateTXT.Text & numSTR
        End While
    End Sub

3 个答案:

答案 0 :(得分:2)

您需要在循环之外声明它并使用Static变量来清除问题。你的循环是快速的,创建导致使用与其他种子相同的种子。 Static变量很好地解决了这个问题。 MSDN Random Class Documentation

  

如果相同的种子用于单独的随机对象,它们将生成相同的随机数序列。这对于创建处理随机值的测试套件或重放从随机数派生数据的游戏非常有用。但是,请注意,在不同版本的.NET Framework下运行的进程中的Random对象可能返回不同系列的随机数,即使它们已使用相同的种子值进行实例化。

Private Sub generateBTN_Click(sender As System.Object, e As System.EventArgs) Handles generateBTN.Click
    ' generateTXT.Clear() 'not needed
    Static rn As New Random
    While generateTXT.Text.Length < 9
        Dim num As Integer = rn.Next(33, 126)
        While num = 40 Or num = 41 Or num = 59 Or num = 61
            num = rn.Next(33, 126)
        End While
        Dim numSTR As String = ChrW(num).ToString
        generateTXT.Text = generateTXT.Text & numSTR
    End While
End Sub

答案 1 :(得分:1)

使用默认构造函数创建Random实例时(如果未传入任何内容),则使用系统时间作为种子。特定种子将始终生成相同的“随机”数字序列。当你在这样的紧密循环中创建一个新的Random实例时,每个实例使用相同的种子,因为没有足够的时间被认为是新的种子。因此,对Next()的调用返回相同的值,因为Random的所有实例都以相同的时间值播种。

这就是为什么在放入断点时获得不同的值;循环迭代之间已经过了足够的时间,被认为是一个新的种子值。

Random类的典型用法是创建在整个应用程序中重用的一个实例。如果Random实例仅在一个sub中使用,则将其声明为static使其不会在运行中被处置(从而防止多个实例使用相同的时间种子问题)。

这是编写代码的另一种方法:

Private Sub generateBTN_Click(sender As System.Object, e As System.EventArgs) Handles generateBTN.Click
    Dim num As Integer
    Static rn As New Random
    Dim sb As New System.Text.StringBuilder
    For i As Integer = 1 To 8
        Do
            num = rn.Next(33, 126)
        Loop While num = 40 Or num = 41 Or num = 59 Or num = 61
        sb.Append(ChrW(num))
    Next
    generateTXT.Text = sb.ToString
End Sub

答案 2 :(得分:1)

之前的两个答案都已正确识别出代码写入的问题,随机播种的值相同。解决问题的另一种方法可以使代码更简洁,并且易于维护。

您有一组有效的密码字符。除了40,41,59和61之外,它们的ASCII范围是33到126.为什么不把它写成它是什么?

Public Shared ReadOnly validChars As String = "!""#$%&'*+,-./0123456789:<>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"

请记住,字符串是一个字符数组。此外,如果用户决定&#34; $&amp; *,该怎么办?将来是不是有效的角色?

<强>方法一:

Public Shared PRNG As New Random
Public Shared ReadOnly validChars As String = "!""#$%&'*+,-./0123456789:<>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"

Private Sub generateBTN_Click(sender As Object, e As EventArgs) Handles generateBTN.Click
    generateTXT.Text = validChars.Select(Function(c) validChars(PRNG.Next(validChars.Length))).Take(8).ToArray
End Sub

如果LINQ让您感到困惑,请尝试此操作。

<强>方法2:

Public Shared PRNG As New Random
Public Shared ReadOnly validChars As String = "!""#$%&'*+,-./0123456789:<>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"

Private Sub generateBTN_Click(sender As Object, e As EventArgs) Handles generateBTN.Click
    Dim sb As New System.Text.StringBuilder
    For x As Integer = 1 To 8
        sb.Append(validChars(PRNG.Next(validChars.Length)))
    Next
    generateTXT.Text = sb.ToString
End Sub

两者完全相同。数字和字符之间没有转换,他们不会浪费周期选择无效的可能性。为了使这些符合OP的代码,我必须查找数字以找出哪些字符是非法的。