使用System.Reflection对象的深层副本?

时间:2015-11-13 15:51:44

标签: c# .net reflection deep-copy

如何在C#中使用System.Reflection执行对象的深层复制?

1 个答案:

答案 0 :(得分:1)

一种简单的方法是使用JSON:

public static T DeepClone<T>(T source)
{
    var serialized = JsonConvert.SerializeObject(source);
    return JsonConvert.DeserializeObject<T>(serialized);
}

为你做反思。显然它不会使用任何东西,例如,有一个非托管对象的句柄等等。

(您可以使用NuGet将Newtonsoft.Json安装到您的项目中。)

默认情况下,Json不会将私有字段序列化。

您可以这样修复:

public static T DeepClone<T>(T source)
{
    var settings = new JsonSerializerSettings {ContractResolver = new MyContractResolver()};
    var serialized = JsonConvert.SerializeObject(source, settings);
    return JsonConvert.DeserializeObject<T>(serialized);
}

public class MyContractResolver : 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;
    }
}

这是一个完整的示例控制台应用程序,显示如何克隆具有私有字段的任意类。请注意Json尝试使用构造函数来设置字段和/或属性,如果构造函数参数名称与字段或属性名称不匹配,则它将无法正常工作:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace ConsoleApplication1
{
    class Test
    {
        public Test(double y, string s, int x)
        {
            this.Y = y;
            this.s = s;
            this.X = x;
        }

        public int X;

        public double Y { get; private set; }

        public string Z         
        {
            get
            {
                return s;
            }
        }

        private string s;
    }

    class Program
    {
        static void Main()
        {
            var test = new Test(1.2345, "12345", 12345);
            test.X = 12345;

            var copy = DeepClone(test);

            Console.WriteLine("X = " + copy.X);
            Console.WriteLine("Y = " + copy.Y);
            Console.WriteLine("Z = " + copy.Z);
        }

        public static T DeepClone<T>(T source)
        {
            var settings = new JsonSerializerSettings {ContractResolver = new MyContractResolver()};
            var serialized = JsonConvert.SerializeObject(source, settings);
            return JsonConvert.DeserializeObject<T>(serialized);
        }

        public class MyContractResolver : 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;
            }
        }
    }
}