2015-11-13 31 views
0

如何在C#中使用System.Reflection对象的深层副本?使用System.Reflection对象的深层副本?

+1

你为什么需要'反思?以及目前为止您尝试的内容 – Habib

+0

属性/字段的递归。问题是要包含哪些内容,如何处理私有字段等等。因此,通过序列化现有序列化和反序列化新序列化,“克隆”对于专门准备好的序列化对象更容易。 – Sinatr

回答

2

一个简单的方法是使用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; 
      } 
     } 
    } 
} 
+1

这不适用于任何对象。对象必须准备好序列化。 – Sinatr

+1

@Sinatr它将适用于许多对象 - 如果您需要使用递归,那么该对象无论如何都必须是可序列化的。 –

+1

@Sinatr JSON.NET是不是像DataContractJsonSerializer ... –