Domanda

Così, ho scritto un piccolo e, da quello che ho inizialmente pensato, metodo facile in C #. Questo metodo statico è pensato per essere usato come un semplice generatore di password suggestione, e gli sguardi codice come questo:

public static string CreateRandomPassword(int outputLength, string source = "")
{
  var output = string.Empty;

  for (var i = 0; i < outputLength; i++)
  {
     var randomObj = new Random();
     output += source.Substring(randomObj.Next(source.Length), 1);
  }

  return output;
}

Io chiamo questa funzione come questa:

var randomPassword = StringHelper.CreateRandomPassword(5, "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");

Ora, questo metodo quasi sempre tornare stringhe casuali come "AAAAAA", "bbbbbb", "888888", ecc .., in cui ho pensato che deve restituire le stringhe come "A8JK2A", "82mOK7", ecc.

Tuttavia, e qui è la parte strano; Se metto un punto di interruzione, e passo attraverso questa linea di iterazione per riga, ottengo il corretto tipo di password in cambio. In 100% degli altri casi, quando Im non il debug, mi dà stronzate come "AAAAAA", "666666", etc ..

Come è possibile? Ogni suggerimento è molto apprezzato! : -)

A proposito, il mio sistema: Visual Studio 2010, C # 4.0, progetto ASP.NET MVC 3 RTM w / ASP.NET Development Server. Non ho ancora testato questo codice in qualsiasi altro ambiente.

È stato utile?

Soluzione

Spostare la dichiarazione per la randomObj fuori del ciclo. Quando sei il debug di esso, si crea con un nuovo seme ogni volta, perché non c'è abbastanza differenza di orario per il seme di essere diversi. Ma quando non sei il debug, il tempo di seme è fondamentalmente la stessa per ogni iterazione del ciclo, in modo che vi sta dando lo stesso valore iniziale ogni volta.

E un minore nit - è una buona abitudine di utilizzare uno StringBuilder piuttosto che una stringa per questo genere di cose, quindi non c'è bisogno di ri-inizializzare lo spazio di memoria ogni volta che si aggiunge un carattere alla stringa.

In altre parole, in questo modo:

public static string CreateRandomPassword(int outputLength, string source = "")
{
  var output = new StringBuilder();
  var randomObj = new Random();
  for (var i = 0; i < outputLength; i++)
  {
     output.Append(source.Substring(randomObj.Next(source.Length), 1));
  }
  return output.ToString();
}

Altri suggerimenti

Il comportamento che stai vedendo è perché Random è basato sul tempo , e quando non sei il debug vola attraverso tutti e 5 iterazioni nello stesso momento (più o meno). Quindi stai chiedendo per il primo numero casuale fuori lo stesso seme. Quando sei il debug, ci vuole abbastanza a lungo per ottenere un nuovo seme ogni volta.

Spostare la dichiarazione di Random fuori del ciclo:

var randomObj = new Random();
for (var i = 0; i < outputLength; i++)
{
    output += source.Substring(randomObj.Next(source.Length), 1);
}

Ora sei in movimento in avanti 5 passi da un seme casuale al posto di in movimento 1 passo dallo stesso seme a caso 5 volte .

Si un'istanza di una nuova istanza di Random () su ogni iterazione del ciclo con un nuovo seme dipendente dal tempo. Data la granularità del clock di sistema e la velocità della CPU moderne, questo praticamente garantisce che si riavvia il sequenza pseudo-casuale più e più volte con lo stesso seme.

Prova qualcosa di simile a quanto segue, anche se se siete single-threaded, si può tranquillamente omettere il blocco ():

private static Random randomBits = new Random() ;
public static string CreateRandomPassword(int outputLength, string source = "")
{
  StringBuilder sb = new StringBuilder(outputLength) ;
  lock ( randomBits )
  {
    while ( sb.Length < outputLength )
    {
      sb.Append( randomBits.Next( source.Length) , 1 ) ;
    }
  }
  return sb.ToString() ;
}

istanziare solo l'RNG volta. Ogni pareggi bit dallo stesso RNG, quindi dovrebbe comportarsi in modo molto più simile ad una fonte di entropia. Se avete bisogno di ripetibilità per il test, utilizzare l'overload del costruttore casuale che consente di fornire il seme. Stesso seme == stessa sequenza pseudo-casuale.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top