如何在C#中使用System.Reflection对对象进行深度复制?
一个简单的方法是使用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;
}
}
}
}