el Guille, la Web del Visual Basic, C#, .NET y más...

Random.Next ese incomprendido

Cómo generar números aleatorios en un rango indicado y que parezcan aleatorios de verdad

 

(29/Nov/18) Números aleatorios con decimales en .NET

 
Publicado el 30/Sep/2007
Actualizado el 29/Nov/2018
Autor: Guillermo 'guille' Som

En este artículo te explico cómo usar correctamente el método Next de la clase Random para generar números aleatorios entre un rango. También te cuento cómo NO debes usar esta clase si quieres que los números de verdad sean aleatorios. Te muestro un ejemplo (tanto para Visual Basic como para C#) para generar una cadena con caracteres aleatorios.



 

La batallita del Guille

Estaba leyendo el número 29 de la revista hakin9 y vi un código en C# para generar cadenas de forma aleatoria (para un motor polimórfico) y al ver el código de esa función, me dio no-se-qué por el cuerpo... y es que usaba de forma errónea la clase Random así como el método Next para generar el siguiente número aleatorio.

Lo malo es que ese tipo de error es muy común. Ya lo había vivido en mis tiempos de Visual Basic 6.0 (y anterior), no por el método Next, ya que en esa versión de Visual Basic las "randomizaciones" se generaban de forma más artesanal y no tenemos ese método mágico. Pero si existía la posibilidad de "hacer mal las cosas" al definir o inicializar la generación de números aleatorios.

Pero dejemos el Visual Basic 6.0 y pasemos a .NET que es lo que ahora interesa.

 

Generar de forma correcta números aleatorios en .NET

En las clases de .NET Framework está la clase Random que sirve para generar números seudo-aleatorios.

Esa clase define varios métodos, pero básicamente usaremos el método Next. Ese método permite que se indiquen dos valores, de esa forma sacará un número aleatorio que esté dentro del rango de esos números indicados.

Y aquí reside el problema, que el valor que genera está DENTRO (o casi) del rango indicado o dicho de otra forma, el valor generado será un número mayor o igual que el primer argumento y menor que el segundo, pero muchos piensan que el número que se genera puede incluir  los dos valores indicados.

En el caso que te comentaba, para generar caracteres aleatorios, usaba esta llamada al método Next:

int e = randomNumber.Next(97, 122);

Seguramente la intención era generar un valor entre 97 y 122, es decir, un valor que devolviera una letra en minúscula desde la a (97) hasta la z (122), pero lo más que puede generar es un valor que va desde el 97 (a) hasta el 121 (y).

Recuerda:
El valor que genera el método Next(n1, n2) es un valor que puede ser igual o mayor que el primer argumento (n1) y menor que el segundo (n2).

El otro fallo garrafal del código ese (no tengo nada en contra del autor, ni lo conozco), pero es que es algo que ya he visto en varios sitios y creo que hacía falta que se aclararan estos conceptos, y como da la casualidad que hoy me he topado con ese código, pues me he dicho: venga Guille, explícalo... además de que también es un tema que tengo incluido en el libro que estoy escribiendo con mis recetas sobre muchas situaciones en las que algunos no saben qué hacer... y mucho más, pero como ese libro estará dirigido para los que usan Visual Basic, he pensado que también es bueno que la gente que usa C# sepan de estas cosas, je, je... pero bueno... dejemos la publicidad de mi nuevo libro y sigamos con esto de los números aleatorios...

Otro fallo que se comete con más frecuencia de la deseada es crear la instancia de la clase Random dentro de un bucle o un método.

Te explico, para que lo entiendas.

La clase Random es la encargada de generar los números aleatorios y permite indicar un valor para usarlo como semilla de los números aleatorios. (No son totalmente aleatorios, -la propia documentación de Visual Studio deja claro que son seudoaleatorios- ya que, según dicen, es casi imposible encontrar un algoritmo que genere números totalmente aleatorios.)

Esa semilla es la que se usa para generar la secuencia de números. Es decir, si usamos siempre la misma semilla, los números aleatorios siempre se generarán en la misma secuencia, por tanto, siempre serán los mismos. (No que siempre se genera el mismo número, sino que si generas 10 números, esos 10 números -que pueden ser diferentes- siempre serán esos mismos 10 números y además generados en el mismo orden.)

 

Un ejemplo que aclare todo esto

En el listado con el código de ejemplo tienes un programa que genera una cadena con la cantidad de caracteres indicados. Los caracteres que incluirá esa cadena estarán comprendidos entre la 'a' y la 'z' (ambos incluidos).

Nota:
Este es el listado para Visual Basic 2005 y este otro para Visual C# 2005.

Ese código se puede usar en versiones posteriores sin cambios, pero para usarlo en versiones anteriores, tendrás que quitar todo el código que manipula la ventana de la consola.

Si ejecutas ese código tal como está en el listado, la salida puede ser como esta:

Milisegundos: 895
01 lawknpfywupmphypupmbttslynnypubgebxxzcbqcfpwwttgdnqietksiklz
02 bgibsjiojbqrowzodwpeuhvcdsckqfporbovxodnlfwbxzuhuwplvgeulfxz
03 hyxembamidqpsbtpkteeyupuqdskwukrregmispvyhzqfattmpjrbsbmicoi
04 jqqntzxovghsejgqvzpqkyxhktqydtefdgmirlwfceyghqmrmkrjmyyksica
05 jzlccboxxxzjcjofarzugyltbvsfibpiiwwctvdfcpupkhgcjsjbjiulorag
06 iiovhqagnllentsqdwiuoqwqrozablocvwwtazhthapyhfnpqdhrjgssmyds
07 raecxjjqxyqeoomnaxjmbjjydwspedgcvobhwmaxvxsrnccutesooqrhqfya
08 qumtsniamfrnxlrdrslatxvalrnfwtrrozgbkzzzucionerdznqyuxhtzlha
09 zcdsnazxfpssslgrpgmhakfidtwqsnczrzarzpametxjuyfjrqesyzzoxupu
10 djfrntaskorzfadhmvnfnnycjjaralueafjuofwbxmycyemywsbbgkhqkcid
11 tiszumzzqisgzmhapveewbvhjtyqytjmxthouzileninzvctchaoydgsnlpa
12 ojbxzgjffsgqnsajthhorenqsuntnoajjhwvlkotlwojbkbfdwzgdajkvkfe
13 sqrqrxgfwexisodupephtipqpufiymabfkavexredwjzyropxourvxlkaabx
14 rygjewcinhqsmldwyqsygqkkrighzpudwumfpzucogbpycfktomkicrbnwsv
15 pujxnmvryyhyvpjaoulpdwnkdkutdlrthymtwdclgnlvhnotsrmskdstgyud
16 rbomgorxcqdlsziqksdqvbalzyiegtmyjyufyzptvqqcnaakvciovdhpacnh
17 fnrjeectfcrlcjuflyyyyyjdkxcfreevmhnizhyjygfskxlliceceoihdnyg
18 cwcaywyuvmfdapartrsnlqwpacqxzgeljrhbeetoyqpwwabpoqomvkulamav
19 fbvphtuihynoxeovbaszaajisrqyxvbrdyixvaodgshpdzpqvzjzubvfrnxq
20 cvlmxvlzvraalpsistfsbacxmbwcddficyalhvshoquezjofjnmxhfocsnzv
21 zjwslsynohawbyekfyydnrtqqiaxjxstvwifucthkbqbmpvjadxupwihqgbd
22 radrohafpzqcfrsmardbmqwgzydynaoobqpkxzneoqtbnvoyewgzcaqbdxrp
23 dbrpkbbpbhobdzmvwvsejfurtpmazogzhxamzermtzwwifvcoueifmgyhavu
24 oapnaoufzzwsdglkjxjoujmekyuurcfyixxtjiwtkqdoyleybvokrgzeoldc
25 tznwtyjgjrabbpdegxgyuwsvnvhbxseyetzkcgvabxpjvnjbcvyqefhxhrjy
26 qhjqncwhptbzcgwwgiaalfybtotzlcdkxwjuoywtqbljuzoyilqyrimlihxy
27 iwvnpqbgxciilhjktohuzvralftpjxlgbyktgyudxiagdimjycsuacymfvcj
28 wmxzrbgnwqevudwrukwcsjqgfrfyzxnlvkglkbobcyniywzxfgsvyzrnvqta
29 whoycszjxlhtwuatwihjrissfsmwttpuhofukoffxqzuzzydyxqnikjnowtj
30 gdpdwmlhpgjhcblaiysftjxwdclwfsfovwzuawynnrosoilhyieqdnqwftat
Milisegundos: 895

Figura 1

Nota:
He modificado los valores del ancho y alto, además de mostrar el valor de los milisegundos transcurridos, que como puedes ver son los mismos en este caso, pero las cadenas son todas diferentes.

Como puedes ver por la salida del ejemplo, (figura 1), el código funciona como se espera: que cada cadena sea diferente, incluso aunque se generen en un "pis-pas".

En ese listado está comentado lo que NO se debe hacer, que te resumo aquí:

1- NO generar la instancia de clase Random, ni la semilla, dentro de un bucle.

Ya que si lo haces, puedes tener la seguridad de que los valores se repitan.

Para probarlo, quita los comentarios que hay en las dos líneas en la que digo Prueba 1 (dentro del bucle del método cadenaAleatoria).

La salida resultante sería la de la figura 2, que si la comparas con la "figura 1", es totalmente NO ALEATORIA.

Milisegundos: 52
01 gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
02 gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
03 gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
04 gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
05 gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
06 gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
07 gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
08 gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
09 gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
10 gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
11 gggggggggggggggggccccccccccccccccccccccccccccccccccccccccccc
12 cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
13 cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
14 cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
15 cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
16 cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
17 cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
18 cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
19 cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
20 cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
21 cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
22 cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
23 cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
24 cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
25 cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
26 ccccccccccccccccccccccccllllllllllllllllllllllllllllllllllll
27 llllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
28 llllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
29 llllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
30 llllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
Milisegundos: 99

Figura 2. Prueba 1

 

2- NO generar la semilla ni la instancia del objeto Random dentro de un método que será llamado de forma consecutiva.

Podías pensar, que si en lugar de crear la instancia dentro del bucle, la creas fuera se soluciona, pero si ese "fuera" es dentro del método, la verdad es que no.

Si vuelves a comentar las dos líneas que te indiqué antes, y le quitas los comentarios a las dos que están dentro del método (la que están indicadas con Prueba 2), verás que la salida es parecida a la de la figura 3 (no tiene porqué ser igual, pero si que no se crean cadenas aleatorias).

Milisegundos: 502
01 zcrswgvhckdktqjowggrnavkxkntfjnreoynwmizxeicpwdieotzltszhgvl
02 zcrswgvhckdktqjowggrnavkxkntfjnreoynwmizxeicpwdieotzltszhgvl
03 zcrswgvhckdktqjowggrnavkxkntfjnreoynwmizxeicpwdieotzltszhgvl
04 zcrswgvhckdktqjowggrnavkxkntfjnreoynwmizxeicpwdieotzltszhgvl
05 zcrswgvhckdktqjowggrnavkxkntfjnreoynwmizxeicpwdieotzltszhgvl
06 zcrswgvhckdktqjowggrnavkxkntfjnreoynwmizxeicpwdieotzltszhgvl
07 zcrswgvhckdktqjowggrnavkxkntfjnreoynwmizxeicpwdieotzltszhgvl
08 zcrswgvhckdktqjowggrnavkxkntfjnreoynwmizxeicpwdieotzltszhgvl
09 zcrswgvhckdktqjowggrnavkxkntfjnreoynwmizxeicpwdieotzltszhgvl
10 zcrswgvhckdktqjowggrnavkxkntfjnreoynwmizxeicpwdieotzltszhgvl
11 zcrswgvhckdktqjowggrnavkxkntfjnreoynwmizxeicpwdieotzltszhgvl
12 zcrswgvhckdktqjowggrnavkxkntfjnreoynwmizxeicpwdieotzltszhgvl
13 zcrswgvhckdktqjowggrnavkxkntfjnreoynwmizxeicpwdieotzltszhgvl
14 zcrswgvhckdktqjowggrnavkxkntfjnreoynwmizxeicpwdieotzltszhgvl
15 zcrswgvhckdktqjowggrnavkxkntfjnreoynwmizxeicpwdieotzltszhgvl
16 zcrswgvhckdktqjowggrnavkxkntfjnreoynwmizxeicpwdieotzltszhgvl
17 zcrswgvhckdktqjowggrnavkxkntfjnreoynwmizxeicpwdieotzltszhgvl
18 zcrswgvhckdktqjowggrnavkxkntfjnreoynwmizxeicpwdieotzltszhgvl
19 zcrswgvhckdktqjowggrnavkxkntfjnreoynwmizxeicpwdieotzltszhgvl
20 ivvdbgzibhxwtzonpesxqynzmshqqgkxpznfckbceqmxazootrpecaxkhwrj
21 ivvdbgzibhxwtzonpesxqynzmshqqgkxpznfckbceqmxazootrpecaxkhwrj
22 ivvdbgzibhxwtzonpesxqynzmshqqgkxpznfckbceqmxazootrpecaxkhwrj
23 ivvdbgzibhxwtzonpesxqynzmshqqgkxpznfckbceqmxazootrpecaxkhwrj
24 ivvdbgzibhxwtzonpesxqynzmshqqgkxpznfckbceqmxazootrpecaxkhwrj
25 ivvdbgzibhxwtzonpesxqynzmshqqgkxpznfckbceqmxazootrpecaxkhwrj
26 ivvdbgzibhxwtzonpesxqynzmshqqgkxpznfckbceqmxazootrpecaxkhwrj
27 ivvdbgzibhxwtzonpesxqynzmshqqgkxpznfckbceqmxazootrpecaxkhwrj
28 ivvdbgzibhxwtzonpesxqynzmshqqgkxpznfckbceqmxazootrpecaxkhwrj
29 ivvdbgzibhxwtzonpesxqynzmshqqgkxpznfckbceqmxazootrpecaxkhwrj
30 ivvdbgzibhxwtzonpesxqynzmshqqgkxpznfckbceqmxazootrpecaxkhwrj
Milisegundos: 518

Figura 3. Prueba 2

 

Resumiendo que es gerundio

Seguro que piensas que usando otra semilla diferente se soluciona, pero la verdad es que no demasiado.

Lo que debes tener en cuenta (y no tener miedo a hacerlo), es la de generar la instancia de la clase Random al inicio del programa, usando una semilla que sea diferente para cada ejecución del programa, por ejemplo, usando el valor de los milisegundos actuales (o el valor de Ticks, como te explico más abajo).
Será mucha casualidad que en dos ejecuciones del programa el valor coincida, pero puede ocurrir...
(A ver, no es normal que ocurra, incluso puede que haya muy pocas probabilidades de que ocurra, sobre todo si se usa Ticks, pero como "posible" de que ocurra, si es posible, je, je.)

En cualquier caso, puedes instanciar el objeto de la clase Random antes de llamar a la función o método que lo vaya a usar, pero asegúrate de que siempre haya algún intervalo entre cada instanciación.

 

Usar un valor más grande para la semilla de Random

También puede que se te haya ocurrido usar DateTime.Now.Ticks como valor de la semilla. La diferencia con DateTime.Now.Millisecond es que el número de Ticks puede ser enorme.

 

Si estás usando Visual Basic, el problema es que Ticks devuelve un valor Long y aunque se haga una conversión a entero, con total seguridad se producirá una excepción de overflow (desbordamiento).

Para solucionarlo debes modificar las propiedades del proyecto para que se quite la comprobación de desbordamiento de enteros:
Propiedades del proyecto, ficha Compilar, botón Opciones de compilación avanzadas y en el primero grupo de opciones (Optimizaciones), habilita la casilla de Quitar comprobaciones de desbordamiento con enteros (en la versión en inglés será Remove integers overflow checks).

La forma de generar una semilla usando Ticks es esta (recuerda deshabilitar las comprobaciones de desbordamiento):

semilla = CInt(DateTime.Now.Ticks)

 

Si estás usando C#, de forma predeterminada la opción esa de comprobación de desbordamiento de enteros está deshabilitada, es decir, no se comprueba el desbordamiento de enteros; pero también puedes usar unchecked para evitar la comprobación de desbordamiento, independientemente de como esté en las propiedades del proyecto:

unchecked
{
    semilla = (int)DateTime.Now.Ticks;
}

o de forma simplificada:

semilla = unchecked( (int)DateTime.Now.Ticks );

 

Nota:
Cuando no se comprueba el desbordamiento de enteros, si asignamos un valor entero de un tipo con más capacidad a otro con menos capacidad, y el valor que tiene el de mayor capacidad excede al valor máximo que puede contener el de menos capacidad, se recortará dicho valor para que quepa correctamente.

Por ejemplo, si tenemos un entero largo (Int64) que tiene el valor 633267851083732000 y lo asignamos a un entero (Int32), el valor que se asignará será: 1599413344.

 

Recuerda: Si quieres, generar números entre 1 y 6 (ambos incluidos), debes usar algo como esto:

n = rnd.Next(1, 7)

 

Y para terminar, una nota de "compatibilidad" con Visual Basic 6.0, (o para los que prefieran usar la función Rnd() de Visual Basic), lo más parecido a esa función es el método NextDouble de la clase Random, el cual genera un número entre 0.0 y 1.0, es decir menor de 1.0 e igual o mayor que 0.0.
Esta función es útil cuando lo que necesitamos son números aleatorios con cifras decimales.

 

(29/Nov/18)
Échale un vistazo a esto: Números aleatorios con decimales en .NET

 

No hay proyectos que bajar, todo el código está más abajo (tanto para VB como para C#).

Decirte también que en el código ese verás que uso un objeto del tipo StringBuilder para ir almacenando los caracteres, para esas cosas en las que se requiere concatenar (unir) caracteres, es mejor usar StringBuilder que String.

 

Y esto es todo... espero que lo aquí comentado te sirva para aclarar las cosas, y sobre todo, te sirva para cuando quieras generar números aleatorios con los valores adecuados.

¡Que lo randomices bien! guiño de complicidad

 

Nos vemos.
Guillermo

 


Código para Visual Basic.NET (VB.NET) El código para Visual Basic 2005 (pero válido para cualquier versión)
'------------------------------------------------------------------------------
' Pruebas de Random.Next                                            (30/Sep/07)
'
' ©Guillermo 'guille' Som, 2007
'------------------------------------------------------------------------------
Option Strict On

Imports Microsoft.VisualBasic
Imports System
Imports System.Text

Module Module1
    Dim semilla As Integer
    Dim rnd As Random


    Sub Main()
        Const ancho As Integer = 100
        Const alto As Integer = 40

        Console.Title = "Generar cadenas aleatorias (VB)"
        Console.WindowWidth = ancho
        Console.WindowHeight = alto

        ' La semilla y el objeto se debe crear
        ' fuera del bucle, así serán todas diferentes
        ' semilla = DateTime.Now.Millisecond

        ' Para que funcione Ticks
        ' debes quitar la comprobación de desbordamiento de enteros
        ' en las propiedades del proyecto, ficha compilación, opciones avanzadas
        semilla = CInt(DateTime.Now.Ticks)

        rnd = New Random(semilla)

        Dim s As String
        Console.WriteLine("Milisegundos: {0:#,#}", DateTime.Now.Ticks)
        For i As Integer = 1 To alto - 5
            s = cadenaAleatoria(ancho - 4)
            Console.WriteLine("{0:00} {1}", i, s)
        Next
        Console.WriteLine("Milisegundos: {0:#,#}", DateTime.Now.Ticks)

        Console.WriteLine()
        Console.WriteLine("Pulsa una tecla")
        Console.ReadKey()


    End Sub

    Function cadenaAleatoria(ByVal longitud As Integer) As String
        ' Un objeto StrngBuilder para mejorar el rendimiento
        ' del manejo de cadenas, además indicando la longitud
        ' el rendimiento es mejor todavía
        Dim s As New StringBuilder(longitud)

        ' El objeto Random para generar los caracteres
        ' con una semilla basada en los milisegundos actuales

        ' Si se genera aquí, y se hacen varias llamadas seguidas
        ' casi todas las cadenas serán iguales

        ' Prueba 2:
        ' Quita estos dos comentarios
        'semilla = DateTime.Now.Millisecond
        'rnd = New Random(semilla)

        ' Un bucle para cada uno de los caracteres
        For i As Integer = 1 To longitud
            ' Si se genera la semilla y el objeto random
            ' dentro del bucle... ¡tu mismo!

            ' Prueba 1:
            ' Quita estos dos comentarios
            'semilla = DateTime.Now.Millisecond
            'rnd = New Random(semilla)

            ' El valor debe ser un carácter válido,
            ' desde la letra a minúscula (97)
            ' hasta la letra z en minúsculas (122)
            Dim c As Char = ChrW(rnd.Next(97, 123))
            ' lo añadimos a la cadena
            s.Append(c)
        Next

        ' Devolvemos la cadena generada
        Return s.ToString
    End Function

End Module

 

Código para C Sharp (C#) El código para C# 2005 (pero válido para cualquier versión)
//-----------------------------------------------------------------------------
// Pruebas de Random.Next                                           (30/Sep/07)
//
// ©Guillermo 'guille' Som, 2007
//-----------------------------------------------------------------------------

using System;
using System.Text;

namespace randomNext_CS
{

class Program
{
    static int semilla;
    static Random rnd;

    static void Main(string[] args)
    {
        const int ancho = 100;
        const int alto = 40;

        Console.Title = "Generar cadenas aleatorias (C#)";
        Console.WindowWidth = ancho;
        Console.WindowHeight = alto;

        // La semilla y el objeto se debe crear
        // fuera del bucle, así serán todas diferentes
        // semilla = DateTime.Now.Millisecond;

        // en C#, por defecto está deshabilitada 
        // la comprobación de desbordamiento de enteros
        semilla = (int)DateTime.Now.Ticks;

        rnd = new Random(semilla);

        string s;
        Console.WriteLine("Milisegundos: {0:#,#}", DateTime.Now.Ticks);
        for(int i = 1; i <= alto - 5; i++)
        {
            s = cadenaAleatoria(ancho - 4);
            Console.WriteLine("{0:00} {1}", i, s);
        }
        Console.WriteLine("Milisegundos: {0:#,#}", DateTime.Now.Ticks);

        Console.WriteLine();
        Console.WriteLine("Pulsa una tecla");
        Console.ReadKey();
    }

    static string cadenaAleatoria(int longitud)
    {
        // Un objeto StrngBuilder para mejorar el rendimiento
        // del manejo de cadenas, además indicando la longitud
        // el rendimiento es mejor todavía
        StringBuilder s = new StringBuilder(longitud);

        // El objeto Random para generar los caracteres
        // con una semilla basada en los milisegundos actuales

        // Si se genera aquí, y se hacen varias llamadas seguidas
        // casi todas las cadenas serán iguales

        // Prueba 2:
        // Quita estos dos comentarios
        //semilla = DateTime.Now.Millisecond;
        //rnd = new Random(semilla);

        // Un bucle para cada uno de los caracteres
        for(int i = 1; i <= longitud; i++)
        {
            // Si se genera la semilla y el objeto random
            // dentro del bucle... ¡tu mismo!

            // Prueba 1:
            // Quita estos dos comentarios
            //semilla = DateTime.Now.Millisecond;
            //rnd = new Random(semilla);

            // El valor debe ser un carácter válido,
            // desde la letra a minúscula (97)
            // hasta la letra z en minúsculas (122)
            char c = (char)(rnd.Next(97, 123));
            // lo añadimos a la cadena
            s.Append(c);
        }

        // Devolvemos la cadena generada
        return s.ToString();
    }
}

}

 


La fecha/hora en el servidor es: 23/12/2024 18:35:21

La fecha actual GMT (UTC) es: 

©Guillermo 'guille' Som, 1996-2024