¿Por qué este método devuelve la misma cadena aleatoria cada vez?
Pregunta
Necesito crear un bloque de líneas únicas para probar un proyecto diferente en el que estoy trabajando.
Entonces creé un programa simple para generar una cadena aleatoria de longitud X.
El problema es que si lo llamo una vez, obtengo una cadena aleatoria, si lo llamo nuevamente (en un bucle for, por ejemplo) obtengo la misma cadena durante toda la ejecución del bucle.
Tengo la sensación de que se está almacenando en caché o algo así, pero no sabía que .net hacía eso y estoy confundido en este punto.
código de llamada:
StreamWriter SW = new StreamWriter("c:\\test.txt");
int x = 100;
while (x >0)
{
SW.WriteLine(RandomString(20));
x--;
}
aquí está el método:
private static string RandomString(int Length)
{
StringBuilder sb = new StringBuilder();
Random randomNumber = new Random();
for (int i = 0; i <= Length; ++i)
{
int x = randomNumber.Next(65, 122);
sb.Append(Convert.ToChar(x));
}
return sb.ToString();
}
y aquí está el resultado:
"VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
..................
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB
VEWMCQ`Fw]TvSFQawYnoB"
Entonces, ¿qué me hace pensar que Random.next() siempre devolvería un nuevo número aleatorio?
Solución
Estás creando el Random
casos demasiado cercanos en el tiempo.Cada instancia se inicializa utilizando el reloj del sistema y, como el reloj no ha cambiado, obtienes la misma secuencia de números aleatorios una y otra vez.
Crear una única instancia del Random
clase y úsala una y otra vez.
Utilizar el using
palabra clave para que el StreamWriter
se cierra y se desecha cuando haya terminado con él.El código de un bucle es más fácil de reconocer si utiliza el for
palabra clave.
using (StreamWriter SW = new StreamWriter("c:\\test.txt")) {
Random rnd = new Random();
for (int x = 100; x > 0; x--) {
SW.WriteLine(RandomString(rnd, 20));
}
}
El método toma la Random
objeto como parámetro.
Además, utilice la longitud para inicializar StringBuilder con la capacidad correcta, de modo que no tenga que reasignarse durante el ciclo.Utilice el operador < en lugar de <= en el bucle; de lo contrario, creará una cadena que tiene un carácter más larga que el length
El parámetro especifica.
private static string RandomString(Random rnd, int length) {
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i++) {
int x = rnd.Next(65, 122);
sb.Append((char)x);
}
return sb.ToString();
}
Otros consejos
Consulte Descripción del constructor aleatorio en MSN, esta parte:
El valor inicial predeterminado se deriva de el reloj del sistema y tiene finito resolución. Como resultado, diferente Objetos aleatorios que se crean en estrecha sucesión por una llamada a la el constructor predeterminado tendrá valores de semilla predeterminados idénticos y, por lo tanto, producirá conjuntos idénticos de números aleatorios.
Entonces, llame al constructor Random () solo una vez al comienzo de su programa o use el constructor Random (int32) y defina una semilla variable usted mismo.
Porque crea un nuevo objeto aleatorio en cada llamada.
Simplemente mueva el randomNumber fuera del método y conviértalo en un miembro de la clase.
private Random randomNumber = new Random();
private static string RandomString(int Length)
{
StringBuilder sb = new StringBuilder();
//...
}
Todos los generadores aleatorios de software son 'pseudoaleatorios', producen una secuencia de bases numéricas en una semilla (inicial). Con la misma semilla producen la misma secuencia. A veces esto es útil. Si desea producir su programa para producir la misma secuencia en cada ejecución, puede usar new Random(0)
.
Editar: aparentemente la clase .Net Random se está auto-sembrando, no lo sabía. Por lo tanto, es un problema de tiempo, como lo han señalado otros.
solo declara randomNumber una vez
public class MyClass
{
private static Random randomNumber = new Random();
private static string RandomString(int Length)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i ... Length; ++i)
{
int x = MyClass.randomNumber.Next(65, 122);
sb.Append(Convert.ToChar(x));
}
return sb.ToString();
}
}
Pregunta similar, muchas respuestas:
generación aleatoria de cadenas: dos generaron una después de otro dar los mismos resultados
la semilla para los números aleatorios son todos iguales debido a la corta cantidad de tiempo que lleva, de hecho, usted recrea el generador aleatorio con la misma semilla cada vez, por lo que la llamada Next () devuelve el mismo valor aleatorio.