2015-11-13 91 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 ... –