如何在C#中保存Random Generator的状态?

Onu*_*nur 11 c# random

出于测试目的,我使用给定的种子创建随机数(即不基于当前时间).

因此整个计划是确定性的.

如果发生了什么事情,我希望能够在"事件发生前不久"迅速恢复一个点.

因此,我需要能够恢复System.Random到以前的状态.

有没有办法提取种子,我可以用来重建随机生成器?

ang*_*son 9

根据这里给出答案,我写了一个小班来帮助保存和恢复状态.

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在LINQPad中测试此代码.


Onu*_*nur 7

这是我想出来的:

基本上它提取私有种子数组。您只需要小心恢复“非共享”数组。

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);

}
Run Code Online (Sandbox Code Playgroud)