Pregunta

Por lo tanto, he escrito un pequeño y, a partir de lo que pensaba inicialmente, método fácil en C #. Este método estático está destinado a ser utilizado como un simple generador de contraseñas sugerencia, y las miradas código como el siguiente:

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

Me llaman a esta función como esta:

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

Ahora, este método casi siempre devuelven cadenas aleatorias como "AAAAAA", "BBBBBB", "888888", etc .., en el que pensé que debería devolver cadenas como "A8JK2A", "82mOK7", etc.

Sin embargo, y aquí está la parte extraña; Si coloco un punto de interrupción, y el paso a través de esta línea de iteración por línea, consigo el tipo correcto de la contraseña a cambio. En el 100% de los otros casos, cuando no estoy de depuración, que me da basura como "AAAAAA", "666666", etc ..

¿Cómo es esto posible? ¡Cualquier sugerencia sera grandemente apreciada! : -)

Por cierto, mi sistema: Visual Studio 2010, C # 4.0, proyecto de ASP.NET MVC 3 RTM w / ASP.NET servidor de desarrollo. no han probado este código en cualquier otro entorno.

¿Fue útil?

Solución

Mover la declaración para el randomObj fuera del bucle. Cuando haya que depurar, se crea con una nueva semilla cada vez, porque no hay suficiente diferencia de tiempo para que la semilla sea diferente. Pero cuando no se está de depuración, el tiempo de la semilla es básicamente el mismo para cada iteración del bucle, por lo que le está dando el mismo valor inicial cada vez.

Y una nit de menor importancia - es un buen hábito de utilizar un StringBuilder en lugar de una cadena para este tipo de cosas, por lo que no tiene que volver a inicializar el espacio de memoria cada vez que se añadirá un carácter a la cadena.

En otras palabras, de esta manera:

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

Otros consejos

El comportamiento que se está viendo es porque Random es basado en el tiempo , y cuando usted no está de depuración que vuela a través de los 5 iteraciones en el mismo momento (más o menos). Por lo que está pidiendo el primer número aleatorio de la misma semilla. Cuando estás depuración, se necesita tiempo suficiente para obtener una nueva semilla cada vez.

Mover la declaración de Random fuera del bucle:

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

Ahora que eres avanzar 5 pasos de una semilla aleatoria en lugar de 1 en movimiento paso de la misma semilla aleatoria 5 veces .

Estás instanciar una nueva instancia de Random () en cada iteración a través del bucle con una nueva semilla dependiente del tiempo. Teniendo en cuenta la granularidad del reloj del sistema y la velocidad de la CPU modernas, esta prácticamente garantiza que se reinicie la secuencia pseudo-aleatoria y otra vez con la misma semilla.

Prueba algo como lo siguiente, aunque si eres un único subproceso, se puede omitir con seguridad el bloqueo ():

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

Sólo una instancia del generador de números aleatorios de una vez. Cada empates bits de la misma generador de números aleatorios, por lo que debe comportarse más como una fuente de entropía. Si necesita repetibilidad de la prueba, utilice el constructor de la sobrecarga aleatorio que permite proporcionar la semilla. Misma semilla == misma secuencia pseudo-aleatoria.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top