How to save the state of a Random generator in C#?

For testing purposes I'm creating random numbers with a given seed (i.e. not based on the current time).

Thus the whole program is deterministic.

If something happens, I'd like to be able to quickly restore a point "shortly before" the incident.

Therefore I need to be able to restore a System.Random to a previous state.

Is there a way to extract a seed which I can use to recreate the random generator?


In line with the answer given here, I wrote a small class to help with saving and restoring the state.

void Main()
{
    var r = new Random();

    Enumerable.Range(1, 5).Select(idx => r.Next()).Dump("before save");
    var s = r.Save();
    Enumerable.Range(1, 5).Select(idx => r.Next()).Dump("after save");
    r = s.Restore();
    Enumerable.Range(1, 5).Select(idx => r.Next()).Dump("after restore");

    s.Dump();
}

public static class RandomExtensions
{
    public static RandomState Save(this Random random)
    {
        var binaryFormatter = new BinaryFormatter();
        using (var temp = new MemoryStream())
        {
            binaryFormatter.Serialize(temp, random);
            return new RandomState(temp.ToArray());
        }
    }

    public static Random Restore(this RandomState state)
    {
        var binaryFormatter = new BinaryFormatter();
        using (var temp = new MemoryStream(state.State))
        {
            return (Random)binaryFormatter.Deserialize(temp);
        }
    }
}

public struct RandomState
{
    public readonly byte[] State;
    public RandomState(byte[] state)
    {
        State = state;
    }
}

You can test this code in LINQPad.


This is what I came up:

Basically it extracts the private seed array. You just need to be careful to restore an "unshared" array.

var first = new Random(100);

// gain access to private seed array of Random
var seedArrayInfo = typeof(Random).GetField("SeedArray", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var seedArray = seedArrayInfo.GetValue(first) as int[];

var other = new Random(200); // seed doesn't matter!

var seedArrayCopy = seedArray.ToArray(); // we need to copy since otherwise they share the array!

seedArrayInfo.SetValue(other, seedArrayCopy);


for (var i = 10; i < 1000; ++i)
{
    var v1 = first.Next(i);
    var v2 = other.Next(i);

    Debug.Assert(v1 == v2);

}