The curious case of the non-random Random()

I was writing some code yesterday, and need to generate different “names” for objects. Rather than using Guid.NewGuid(), I decided (for no clear reason) to append a random int generated by System.Random, with code looking something like that:

public string CreateRandomName()
{
    Random randomizer = new Random();
    return randomizer.Next().ToString();
}

All looked great, until I wrote code like this:

[Test]
public void CreateInstancesWithDifferentNames()
{
    var firstInstance = new MyClass();
    firstInstance.Name = CreateRandomName();
    var secondInstance = new MyClass();
    secondInstance.Name = CreateRandomName();
    Assert.AreNotEqual(firstInstance.Name, secondInstance.Name);
}

I expected each instance to have a different name, but the test fails miserably. Both instances get a random number, but… they get the same random number.

What really threw me off was that the first thing I did was to add a breakpoint in the test to see what was going on - and every time I would step into the code, the test would pass. This sounded like a Schroedinger cat moment: by merely observing the system I was changing its behavior.

I believe I figured out the source of the problem. Of course, Random does not produce “random” numbers, but rather a pseudo-random series, generated from a seed value. When you use the empty constructor for Random(), the seed is set to a value based off the clock; and because my two calls were taking place so close from each other, the seed must have been set to the same value. I am not totally sure about this, but when I added a “delaying” loop in my code, everything worked fine:

[Test]
public void CreateInstancesWithDifferentNames()
{
    var firstInstance = new MyClass();
    firstInstance.Name = CreateRandomName();
    for (int i = 0; i < 1000000; i++) { }
    var secondInstance = new MyClass();
    secondInstance.Name = CreateRandomName();
    Assert.AreNotEqual(firstInstance.Name, secondInstance.Name);
}

The take-away of the story - be careful when using Random, because you might end up with surprisingly less randomness than what you expect…

Do you have a comment or a question?
Ping me on Mastodon!