Do You Know Random Will Generate the Same Result?
2014/11/012 min read
bookmark this
Table of Contents
Introduction
I wrote an IEnumerable extension and discovered an unexpected behavior with C#'s Random class — it can generate the same result when instantiated multiple times in quick succession.
The Problem
I wrote the following extension method that uses Random:
return source.Select(x => new
{
Index = RandomGenerator.Next,
Value = x
})
Do you know that the result will return the same number if I run the extension I created 100 times?
The Unit Test
[TestMethod]
public void Linq_AfterShuffle100TimesResultShouldBeContainsAllValues()
{
List target = new List { 1,2,3,4,5,6,7,8,9,10 };
List resultCheck = new List();
for (int i = 0; i < 100; i++)
{
resultCheck.Add(target.Shuffle(1).ToList().FirstOrDefault());
}
resultCheck = resultCheck.Distinct().OrderBy(x => x).ToList();
Assert.IsTrue(target.Count() == resultCheck.Count());
for (int i = 0; i < target.Count - 1; i++)
{
Assert.AreEqual(target[i], resultCheck[i]);
}
Assert.AreEqual(10, resultCheck.Count());
}
I totally didn't notice this until I checked the MSDN documentation on Random.
The Solution: Singleton Random Generator
So I had to create a single instance of the Random object:
public static class RandomGenerator
{
private static Random _random;
private static object _instance = new object();
static RandomGenerator()
{
_random = new Random();
}
private static Random GetObject
{
get
{
lock (_instance)
{
if (_random == null)
{
_random = new Random();
}
return _random;
}
}
}
public static int Next
{
get
{
return _random.Next();
}
}
}
Conclusion
Unit testing is so important. If you write code using TDD, you'll notice problems like this and become a better developer. Always use a single instance of Random to avoid generating the same sequence of numbers when creating multiple instances in quick succession.