Laden...

Sehr seltsames Problem mit Random

Erstellt von epic_fail vor 14 Jahren Letzter Beitrag vor 14 Jahren 991 Views
epic_fail Themenstarter:in
33 Beiträge seit 2009
vor 14 Jahren
Sehr seltsames Problem mit Random

Es geht um einen Passwortgenerator der pro Runde (wird als Parameter bei GetNewPassword() definiert) 4 Zufallscharacters aussuchen soll. Einen Gross- und einen Kleinbuchstaben, ein Sonderzeichen und eine Zahl. Bei mehreren Runden werden die Blöcke zusammengefügt und ergeben ein Passwort. Demnach ist ein Passwort mit 1 Runde 4 Zeichen lang, 2 Runden sind 8 Zeichen, 3 Runden sind 12 Zeichen usw.

public partial class Test : System.Web.UI.Page
{

    /// <summary>
    /// This Hashtable will contain different <c>char</c> arrays, filled with allowed characters 
    /// </summary>
    private Hashtable charactersHashtable;

    protected void Page_Load(object sender, EventArgs e)
    {
        charactersHashtable = new Hashtable();
        charactersHashtable.Add(0, "!#$%_=+".ToCharArray());
        charactersHashtable.Add(1, "0123456789".ToCharArray());
        charactersHashtable.Add(2, "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray());
        charactersHashtable.Add(3, "abcdefghijklmnopqrstuvwxyz".ToCharArray());
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        TextBox1.Text = GetNewPassword(3);
    }

    private string GetRandomChar(int hashtableKey)
    {
        char[] c = (char[])charactersHashtable[hashtableKey];

        Random rand = new Random();

        int lower = (int)c.GetLowerBound(0);
        //Response.Write(lower + ",");
        int upper = (int)c.GetUpperBound(0);
        //Response.Write(upper + ",");
            
        int randomCharPosition = rand.Next(lower, upper);
        //Response.Write("[<strong>" + randomCharPosition + "</strong>],");

        return c[randomCharPosition].ToString();
    }

    /// <summary>
    /// Gets the new password.
    /// </summary>
    /// <param name="passwordStrength">Number of rounds, in other words the password strength. Every round creates a block of 4 index keys for the hashtable</param>
    /// <returns>The new generated password</returns>
    public string GetNewPassword(int passwordStrength)
    {

        StringBuilder pwdBuffer = new StringBuilder();
        Queue keysQueue = new Queue();
        Random rand = new Random();

        for (int i = 0; i < passwordStrength; i++)
        {
            // Queue object will be created every round depending on passwordStrength
            Queue rounds = new Queue();

            for (int ii = 0; ii < 4; ii++)
            {
                
                int current = rand.Next(0, 4);
                if (rounds.Contains(current))
                {
                    ii--;
                }
                else
                {
                    rounds.Enqueue(current);
                    keysQueue.Enqueue(current);
                }
                
            }
        }

        int count = keysQueue.Count;

        for (int i = 0; i < count; i++)
        {
            int hashtableKey = Convert.ToInt32(keysQueue.Dequeue());
            string randomChar = GetRandomChar(hashtableKey);

            //**********************
            // Wenn ich hier einen Breakpoint setze und debugge, funktioniert Random tadellos
            //**********************
            pwdBuffer.Append(randomChar);
        }

        //**********************
        // Wenn ich hier einen Breakpoint setze und debugge, generiert Random 4 Zufallszahlen, aber wiederholt diese dann jede Runde.
        // Also wenn ich ein Passwort mit Stärke 3 generiere (siehe Button1_Click()) kriege ich 4 Zufallszahlen, 3 mal wiederholt.
        //**********************
        return pwdBuffer.ToString();

    }

}

Am Schluss von GetNewPassword() steht in Kommentaren, was schief läuft. Es ist echt seltsam. Der einzige Unterschied bei den Breakpoints ist, dass man beim oberen Breakpoint jeden einzelnen Aufruf von GetRandomChar() mitverfolgen kann und beim unteren nicht. Zurückgeben das Ergebnis sollte aber gleich aussehen. Ich bin echt am Ende meines Lateins.

830 Beiträge seit 2005
vor 14 Jahren

Hallo epic_fail.

Du darfst Random nicht immer wieder neu erzeugen, sondern du musst eine Instanz halten.

Gruss
Friedel

Ohne Ziel ist auch der Weg egal.

epic_fail Themenstarter:in
33 Beiträge seit 2009
vor 14 Jahren

Oh mann.... DANKE!!! Das wars 😄

3.971 Beiträge seit 2006
vor 14 Jahren

Random berechnet Zufallszahlen (Pseudozufallszahlen) von einem Startwert (Seed) aus. Gibts du bei der Instanzierung einen anderen Seed an, bekommst du auch unterschiedliche Zufallszahlen. Standard Seed ist beispielsweise die aktuelle zeit.

PS: auch gut als Seed zu gebrauchen sind Guids:


Random rnd = new Random(Guid.NewGuid().GetHashCode());

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

epic_fail Themenstarter:in
33 Beiträge seit 2009
vor 14 Jahren

Ich muss einen Start und Endwert angeben. Deshalb übergebe ich der Next() Methode den Lower- bzw. UpperBound eines arrays.

Was ich aber nicht verstehe: Warum wurde beim Debuggen trotzdem das richtige Ergebnis erstellt? Ist das ein Bug von VS? Wenn ich nun die Lösung so anschaue hätte ich sogar ein Compilerfehler erwartet...

5.941 Beiträge seit 2005
vor 14 Jahren

Hallo epic_fail

Standardmässig ist der Seed AFAIK von der Uhrzeit abgeleitet.
Wenn du im Debugger testest, verfälscht das das Ergebnis. Es ist also eine Frage des Timings.

Gruss Peter

--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011