Question

Alors, je l'ai écrit un petit, de ce que je pensais au départ, méthode simple en C #. Cette méthode statique est destiné à être utilisé comme un simple générateur de suggestion de mot de passe, et le look de code comme ceci:

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;
}

J'appelle cette fonction comme ceci:

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

Maintenant, cette méthode presque toujours revenir des chaînes aléatoires comme "AAAAAA", "BBBBBB", "888888" etc .., où je pensais qu'il devrait retourner des chaînes comme "A8JK2A", "82mOK7" etc.

Cependant, et voici la partie wierd; Si je place un point d'arrêt, et pas à travers cette ligne d'itération en ligne, je reçois le type de mot de passe en retour correct. Dans 100% des autres cas, quand je ne suis pas le débogage, il me donne la merde comme "AAAAAA", "666666", etc ..

Comment est-ce possible? Toute suggestion est grandement appréciée! : -)

BTW, mon système: Visual Studio 2010, C # 4.0, ASP.NET MVC 3 projet RTM w / ASP.NET Development Server. Ont pas testé ce code dans tout autre environnement.

Était-ce utile?

La solution

Déplacer la déclaration pour la randomObj en dehors de la boucle. Lorsque vous le débogage, il crée avec une nouvelle semence à chaque fois, parce qu'il ya assez de différence de temps pour que la semence soit différente. Mais quand vous n'êtes pas le débogage, le temps de démarrage est fondamentalement la même pour chaque itération de la boucle, il te donne la même valeur de départ à chaque fois.

Et un mineur nit - c'est une bonne habitude d'utiliser un StringBuilder plutôt qu'une chaîne pour ce genre de chose, de sorte que vous n'avez pas à ré-initialiser l'espace mémoire à chaque fois que vous ajoutez un caractère à la chaîne.

En d'autres termes, comme ceci:

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();
}

Autres conseils

Le comportement que vous voyez est parce que Random est en fonction du temps , et quand vous n'êtes pas le débogage il vole à travers les 5 itérations au même moment (plus ou moins). Donc, vous demandez le premier nombre aléatoire de la même graine. Lorsque vous avez le débogage, il faut assez longtemps pour obtenir une nouvelle semence à chaque fois.

Déplacer la déclaration de Random en dehors de la boucle:

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

Maintenant, vous êtes aller de l'avant 5 pas d'une graine aléatoire au lieu de en mouvement 1 pas de la même graine aléatoire 5 fois .

Vous instanciation d'une nouvelle instance de Random () à chaque itération dans la boucle avec une nouvelle semence en fonction du temps. Compte tenu de la granularité de l'horloge du système et la vitesse des processeurs modernes, ce à peu près garantie que vous redémarrez la séquence pseudo-aléatoire à plusieurs reprises avec la même graine.

Essayez quelque chose comme ce qui suit, mais si vous êtes seul thread, vous pouvez sans risque omettre le verrou ():

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() ;
}

Vous n'instancier la RNG fois. Tous les tirages morceaux de la même RNG, il devrait donc se comporter beaucoup plus comme une source d'entropie. Si vous avez besoin de répétabilité pour les tests, utilisez la surcharge constructeur aléatoire qui permet de fournir la semence. graine même == même séquence pseudo-aléatoire.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top