No tan aleatorio (System.Random)

Cuando estaba en el Club .NET, sorteabamos quién se iba de viaje con una aplicación propia que varios de nuestros compañeros habían creado… sinceramente, no sé exactamente como estaba implementada, pero creo que hacía uso de System.Random…

La aplicación tomaba una lista con los participantes e iba repartiendo “votos” a cada uno de los apuntados… los seleccionaba utilizando Random.Next(numeroDeParticipantes)…

Así es como recuerdo que estaba hecha cuando la miré en su día (ahora estoy intentando conectarme al Subversion pero no hay manera), espero que lo hayan cambiado.

La cosa es la siguiente: si ejecutais el código que viene a continuación, vereis un resultado inesperado.

Random random;
for (int j = 0; j < 10; j++)
{
    random = new Random(30);
    for (int i = 0; i < 10; i++)
        Console.Write(random.Next(10) + " ");

    Console.WriteLine();
}

Y la salida por consola será la siguiente:
3 6 7 9 7 7 3 4 6 3
3 6 7 9 7 7 3 4 6 3
3 6 7 9 7 7 3 4 6 3
3 6 7 9 7 7 3 4 6 3
3 6 7 9 7 7 3 4 6 3
3 6 7 9 7 7 3 4 6 3
3 6 7 9 7 7 3 4 6 3
3 6 7 9 7 7 3 4 6 3
3 6 7 9 7 7 3 4 6 3
3 6 7 9 7 7 3 4 6 3

¿Qué está pasando? Cada vez que creas una nueva instancia de System.Random, puedes pasarle como valor una “semilla”, un Int32. Si le pones una constante (en este caso 30), vas a ver que los resultados siempre van a ser los mismos. ¿Por qué? Para facilitar el debugging de programa.

Entonces… ¿qué hacemos? La mejor recomendación en estos casos es utilizar el constructor vacío de la clase Random, para que utilice cualquiera de las 2^32 secuencias. Sin embargo, hay que tener en cuenta una cosa: esta clase no genera números aleatorios sino pseudoaleatorios.

Si realmente necesitas números aleatorios, lo mejor es utilizar RNGCryptoServicesProvider o alguna propia (desrecomendado a no ser que seas un crack) que funcione en base a la fecha/mac/etc… o incluso alguna utilizando por debajo System.Guid.NewGuid().

Mas información:
Random (Clase) (System)
Guid (Estructura)
RNGCryptoServiceProvider (Clase)

No tan aleatorio (System.Random)