Why does a Random instance in a serialized class repeatedly produce the same set of numbers?

So I'm C # noob. I have a quick question that I can not find the answer anywhere.

[Serializable()] public class Dictionary { private Random m_RandomGenerator = new Random(); public int GetNext() { return m_RandomGenerator.Next(100); } } 

A Dictionary instance is loaded every time the program starts, and this code will return the exact same sequence of numbers each time it starts. By this I mean, every time the executable is launched. Of course, the value of the time it populated should be different (DateTime.Now.Ticks, I assume?).

A few points:

  • At startup, there is only one dictionary instance deserialized from a file with a previously exported file.
  • If I create a static m_RandomGenerator file, the problem will be fixed.

Does anyone know why? I double-checked that every time I did not create a new instance of the dictionary, so this is not a problem.


Ok, color me embarrassment. As it turned out, the attribute [Serializable ()] was the culprit. The dictionary class that I used was loaded from a previously exported file, which obviously loaded the seed back into Random (). Changing the variable to static meant that the initial value was no longer loaded from a previously serialized instance - hiding the problem.

Thanks to all the people offering constructive advice!

+7
source share
5 answers

(CW, because it is too important for comment)

This test will be repeated only when Random is selected. You should publish the code that calls the dictionary, because there might be something suspicious (provided that the code is sent - this is the actual code) or even better to post your own test that reproduces the problem.

 [Test] public void TestDictionary() { var dictionary = new Dictionary(); for(int i = 0; i < 10; i++) { Console.WriteLine(dictionary.GetNext()); } } [Serializable] // added after the fact public class Dictionary { //private Random m_RandomGenerator = new Random(12); private Random m_RandomGenerator = new Random(); public int GetNext() { return m_RandomGenerator.Next(100); } } 

This test repeats your results, but because of the answer here :

 [Test] public void TestDictionary2() { var alpha = new Dictionary(); var bravo = new Dictionary(); for(int i = 0; i < 10; i++) { Console.WriteLine("{0} - {1}", alpha.GetNext(), bravo.GetNext()); } } 

For completeness, serialization testing has been done here:

 [Test] public void SerializationPerhaps() { var charlie = new Dictionary(); Dictionary delta = null; // Borrowed from MSDN: http://msdn.microsoft.com/en-us/library/system.serializableattribute.aspx //Opens a file and serializes the object into it in binary format. using (var stream = File.Open("data.xml", FileMode.Create)) { var formatter = new BinaryFormatter(); formatter.Serialize(stream, charlie); } //Opens file "data.xml" and deserializes the object from it. using (var stream = File.Open("data.xml", FileMode.Open)) { var formatter = new BinaryFormatter(); delta = (Dictionary) formatter.Deserialize(stream); stream.Close(); } for(int i = 0; i < 10; i++) { Assert.AreEqual(charlie.GetNext(), delta.GetNext()); } } 
+6
source

The source of your problem should be somewhere else besides the code you posted. Here is the same code embedded in the test harness:

 using System; namespace RandomTest { public class Dictionary { private Random m_RandomGenerator = new Random(); public int GetNext() { return m_RandomGenerator.Next(100); } } class Program { static void Main(string[] args) { Dictionary d = new Dictionary(); for (int i=0;i<10;i++) { int r = d.GetNext(); Console.Write("{0} ",r); } Console.WriteLine(); } } } 

It returns a different sequence each time it starts.

+1
source

Well, without additional code examples, the answer to your question is simple.

This is not repeated.

I plugged your sample code into a console application and the result is completely random.

 namespace Sandbox { class Program { static void Main(string[] args) { Dictionary dict = new Dictionary(); for (int count = 0; count < 100; count++) Console.WriteLine(dict.GetNext()); Console.ReadLine(); } } public class Dictionary { private Random m_RandomGenerator = new Random(); public int GetNext() { return m_RandomGenerator.Next(100); } } } 

Result:

http://www.codetunnel.com/content/images/random.jpg

+1
source

I don’t know what exactly you want, but it helps me solve my problem. Your post and another answer, comments lead me to this.

 using System; using System.IO; using System.Runtime.Serialization.Formatters.Binary; namespace SerializeRandom { [Serializable] // added after the fact public class RandomGenerator { const string fileName = "random.bin"; private Random random = new Random(); public int GetNext() { return random.Next(100); } public static void Save(RandomGenerator obj) { using (var stream = File.Open(fileName, FileMode.Create)) { var formatter = new BinaryFormatter(); formatter.Serialize(stream, obj); } } public static RandomGenerator Load() { RandomGenerator randomGenerator = null; //create new object if file not exist if (!File.Exists(fileName)) { randomGenerator = new RandomGenerator(); } else { //load from bin file using (var stream = File.Open(fileName, FileMode.Open)) { var formatter = new BinaryFormatter(); randomGenerator = (RandomGenerator)formatter.Deserialize(stream); stream.Close(); } } return randomGenerator; } } } 

and testing class

 using System.Collections.Generic; using NUnit.Framework; namespace SerializeRandom { public class RandomGeneratorTest { [Test] public void TestDictionary1() { var randomGenerator = RandomGenerator.Load(); var randomResult1 = new List<int>(); for (int i = 0; i < 10; i++) { randomResult1.Add(randomGenerator.GetNext()); } RandomGenerator.Save(randomGenerator); randomGenerator = RandomGenerator.Load(); var randomResult2 = new List<int>(); for (int i = 0; i < 10; i++) { randomResult2.Add(randomGenerator.GetNext()); } CollectionAssert.AreNotEqual(randomResult1, randomResult2); } } } 
0
source

This is because it (Random()) is a pseudo-random number generator.

Initializing a random number generator requires a seed to make it non-repeating.

An acceptable choice is to use computer time as a seed.

However, since the clock has finite resolution, using a parameterless constructor to create different random objects with a close sequence creates random number generators that produce identical sequences of random numbers.

http://msdn.microsoft.com/en-us/library/system.random.aspx

I will be careful with the default constructor without parameters.

-3
source

All Articles