Reputation: 141
This block is supposed to generate a random 8 character password. When tested, it displays the same 8 characters in the textbox. If I go line by line for the entire iteration, it works properly. If I go line by line for a few loops, then let it run the rest of the characters will be repeat. For example, I break for 3 lines and then resume: abcddddd is my output.
What is causing this to happen?
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
Upvotes: 0
Views: 58
Reputation: 11773
Both previous answers have correctly identified the problem with your code as written, the random is being seeded with the same value. A different approach to the problem results in more succinct code and that is easily maintainable.
You have a set of valid characters for the password. They are in the ASCII range of 33 to 126 except for 40, 41, 59, and 61. Why not write that as what it is?
Public Shared ReadOnly validChars As String = "!""#$%&'*+,-./0123456789:<>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
Remember that a string is an array of characters. Also, what if the users decide that "$&*,. aren't valid characters in the future?
Method1:
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
If LINQ is confusing to you try this.
Method2:
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
Both do the exact same thing. There is no conversion between numbers and characters and they don't waste cycles choosing invalid possibilities. In order to get these to match the OP's code I had to look up numbers to find out which characters were illegal.
Upvotes: 1
Reputation: 39152
When you create an instance of Random using the default constructor (when you don't pass in anything), it uses the system time as the seed. A specific seed will always generate the same sequence of "random" numbers. When you create a new instance of Random in a tight loop like that, the same seed gets used for each instance because not enough time has transpired to be considered a new seed. Therefore the calls to Next() return the same value since all the instances of Random were seeded with the same time value.
This is why you get different values when you put breakpoints in; enough time has passed between iterations of the loop to be considered a new seed value.
Typical usage of the Random class is to create one instance that gets reused across the whole application. If the Random instance is to be used only within one sub, then declaring it as static
keeps it from being disposed across runs (thus preventing the multiple instances using the same time seed problem).
Here's an alternate way to write your code:
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
Upvotes: 1
Reputation: 9024
You need to declare it outside of the loop and using a Static
variable will clean up the problem. Your loop is to fast and the creation was causing to use the same seed as the others. The Static
variable fixes that problem nicely. MSDN Random Class Documentation
If the same seed is used for separate Random objects, they will generate the same series of random numbers. This can be useful for creating a test suite that processes random values, or for replaying games that derive their data from random numbers. However, note that Random objects in processes running under different versions of the .NET Framework may return different series of random numbers even if they're instantiated with identical seed values.
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
Upvotes: 2