System.Random的深层克隆

xar*_*eth 6 .net c# random serialization

我正在尝试深度克隆包含System.Random变量的对象.我的应用程序必须是确定性的,因此我需要捕获随机对象状态.我的项目基于.Net Core 2.0.

我在这里使用了一些深度克隆代码(你如何在.NET(特别是C#)中对对象进行深度复制?)使用序列化.

System.Random的文档是混合的:

序列化

不可序列化

我收到以下错误.

System.Runtime.Serialization.SerializationException HResult = 0x8013150C Message =在程序集'System.Private.CoreLib中输入'System.Random',Version = 4.0.0.0,Culture = neutral,PublicKeyToken = 7cec85d7bea7798e'未标记为可序列化.来源= System.Runtime.Serialization.Formatters

System.Random可以按我想要的方式克隆吗?

我创建了一个小程序来说明.

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace RandomTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Container C = new Container();
            Container CopyC = DeepClone(C);
        }

        public static T DeepClone<T>(T obj)
        {
            using(var ms = new MemoryStream())
            {
                var formatter = new BinaryFormatter();
                formatter.Serialize(ms, obj); //<-- error here
                ms.Position = 0;

                return (T)formatter.Deserialize(ms);
            }
        }
    }

    [Serializable]
    public class Container
    {
        public ObjectType AnObject;
        public Container()
        {
            AnObject = new ObjectType();
        }
    }

    [Serializable]
    public class ObjectType
    {
        //[NonSerialized]  // Uncommenting here removes the error
        internal System.Random R;
    }
}
Run Code Online (Sandbox Code Playgroud)

我可能不需要Container对象,但这个结构更像我的应用程序.

使R [NonSerialized]删除错误但在反序列化后我没有得到我的Random对象.我尝试重新创建随机对象,但它启动了一个新的随机序列,因此打破了确定性要求.

Mat*_*son 1

你可以用来JSON.NET做这个。

使用项目| 管理 NuGet 包以将“Newtonsoft.Json”(最新稳定版本 10.0.3)添加到您的项目中。

然后你可以编写一个Cloner使用 Json.NET 克隆对象的类:

public static class Cloner
{
    public static T Clone<T>(T source)
    {
        if (ReferenceEquals(source, null))
            return default(T);

        var settings = new JsonSerializerSettings { ContractResolver = new ContractResolver() };

        return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source, settings), settings);
    }

    class ContractResolver : DefaultContractResolver
    {
        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            var props = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                .Select(p => base.CreateProperty(p, memberSerialization))
                .Union(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                    .Select(f => base.CreateProperty(f, memberSerialization)))
                .ToList();
            props.ForEach(p => { p.Writable = true; p.Readable = true; });
            return props;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以编写一些代码,如下所示:

var inner = new ObjectType {R = new Random(12345)};
var outer = new Container  {AnObject = inner};

var clone = Cloner.Clone(outer);

Console.WriteLine(clone.AnObject.R.Next()); // Prints 143337951
Console.WriteLine(outer.AnObject.R.Next()); // Also prints 143337951
Run Code Online (Sandbox Code Playgroud)