使用 System.Reflection 对象的深拷贝?
Deep copy of objects using System.Reflection?
如何在 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;
}
}
这是一个完整的示例控制台应用程序,展示了如何克隆具有私有字段的任意 class。请注意,Json
尝试使用构造函数来设置字段 and/or 属性,如果构造函数参数名称与字段或 属性 名称不匹配,它将无法正常工作:
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;
}
}
}
}
如何在 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;
}
}
这是一个完整的示例控制台应用程序,展示了如何克隆具有私有字段的任意 class。请注意,Json
尝试使用构造函数来设置字段 and/or 属性,如果构造函数参数名称与字段或 属性 名称不匹配,它将无法正常工作:
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;
}
}
}
}