Do You Know Random Will Generate the Same Result?

2014/11/012 min read
bookmark this
Responsive image

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.