views:

5921

answers:

7

Hi, I've developed a random string generator but it's not behaving quite as I'm hoping. My goal is to be able to run this twice and generate two distinct four character random strings. However, it just generates one four character random string twice.

Here's the code and an example of its output:

private string RandomString(int size)
    {
        StringBuilder builder = new StringBuilder();
        Random random = new Random();
        char ch;
        for (int i = 0; i < size; i++)
        {
            ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));                 
            builder.Append(ch);
        }

        return builder.ToString();
    }

// get 1st random string 
string Rand1 = RandomString(4);

// get 2nd random string 
string Rand2 = RandomString(4);

// creat full rand string
string docNum = Rand1 + "-" + Rand2;

...and the output looks like this: UNTE-UNTE ...but it should look something like this UNTE-FWNU

How can I ensure two distinct random strings?

Thanks!

+37  A: 

You're instantiating the Random object inside your method.

The Random object is seeded from the system clock, which means that if you call your method several times in quick succession it'll use the same seed each time, which means that it'll generate the same sequence of random numbers, which means that you'll get the same string.

To solve the problem, move your Random instance outside of the method itself (and while you're at it you could get rid of that crazy sequence of calls to Convert and Floor and NextDouble):

private readonly Random _rng = new Random();
private const string _chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

private string RandomString(int size)
{
    char[] buffer = new char[size];

    for (int i = 0; i < size; i++)
    {
        buffer[i] = _chars[_rng.Next(_chars.Length)];
    }
    return new string(buffer);
}
LukeH
Or make it static and internal to the class.
Jake Pearson
Also, I like making this sort of method an extension method on Random.
Cameron MacFarland
Note that instance members of the Random class are NOT documented as being thread-safe, so if this method is called from multiple threads at the same time (highly likely if you're making a web app, for example) then the behaviour of this code will be undefined. You either need to use a lock on the random or make it per-thread.
Greg Beech
+1  A: 

This is because each new instance of Random is generating the same numbers from being called so fast. Do not keep creating a new instance, just call next() and declare your random class outside of your method.

John T
+2  A: 

You should have one class-level Random object initiated once in the constructor and reused on each call (this continues the same sequence of pseudo-random numbers). The parameterless constructor already seeds the generator with Environment.TickCount internally.

kek444
+8  A: 

You're making the Random instance in the method, which causes it to return the same values when called in quick succession. I would do something like this:

private static Random random = new Random((int)DateTime.Now.Ticks);//thanks to McAden
private string RandomString(int size)
    {
        StringBuilder builder = new StringBuilder();
        char ch;
        for (int i = 0; i < size; i++)
        {
            ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));                 
            builder.Append(ch);
        }

        return builder.ToString();
    }

// get 1st random string 
string Rand1 = RandomString(4);

// get 2nd random string 
string Rand2 = RandomString(4);

// creat full rand string
string docNum = Rand1 + "-" + Rand2;

(modified version of your code)

RCIX
Thanks RCIX, I went with your example and it's working!
PushCode
You're very welcome! i don't suppose you would mind accepting this answer... :)
RCIX
Note that instance members of the `Random` class are NOT documented as being thread-safe, so if this method is called from multiple threads at the same time (highly likely if you're making a web app, for example) then the behaviour of this code will be undefined. You either need to use a lock on the random or make it per-thread.
Greg Beech
A: 

So, is it as simple as changing

This line: Random random = new Random();

To this: Random random = new Random((int)DateTime.Now.Ticks);

Or is there more to it than that?

PushCode
Luke's answer is what you want. And please use comments for commenting or asking a follow-up question to an answer. Answers are for answering.
Chris W. Rea
A: 

Here is a blog post that provides a bit more robust class for generating random words, sentences and paragraphs:

http://nickstips.wordpress.com/2010/08/26/c-random-text-generator/

Nick Olsen
A: 

If you wanted to generate a string of Numbers and Characters for a strong password.

private static Random random = new Random();

private static string CreateTempPass(int size)
        {
            var pass = new StringBuilder();
            for (var i=0; i < size; i++)
            {
                var binary = random.Next(0,2);
                switch (binary)
                {
                    case 0:
                    var ch = (Convert.ToChar(Convert.ToInt32(Math.Floor(26*random.NextDouble() + 65))));
                        pass.Append(ch);
                        break;
                    case 1:
                        var num = random.Next(1, 10);
                        pass.Append(num);
                        break;
                }
            }
            return pass.ToString();
        }
CGsoldier
Note that instance members of the Random class are NOT documented as being thread-safe, so if this method is called from multiple threads at the same time (highly likely if you're making a web app, for example) then the behaviour of this code will be undefined. You either need to use a lock on the random or make it per-thread.
Greg Beech