2012-06-17 128 views
6

我正在編寫用C#編寫的代碼。在這個應用程序,我有一個自定義集合定義如下:C#對象的深拷貝

public class ResultList<T> : IEnumerable<T> 
{ 
    public List<T> Results { get; set; } 
    public decimal CenterLatitude { get; set; } 
    public decimal CenterLongitude { get; set; } 
} 

結果使用的類型是三種自定義類型之一。每個自定義類型的屬性都只是原始類型(ints,strings,bools,int?,bool?)。下面是一個自定義類型的示例:

public class ResultItem 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 
    public bool? isLegit { get; set; } 
} 

如何執行我創建的ResultList對象的深層副本。我發現這個職位:Generic method to create deep copy of all elements in a collection。但是,我無法弄清楚如何去做。

+0

你嘗試過什麼?你有什麼錯誤信息?你發現的Jon Skeet的代碼只要我能看到就行。 –

+0

淺或深的副本? http://stackoverflow.com/questions/11073196/shallow-copy-of-a-custom-c-sharp-object –

+0

爲什麼你和[這個queston]的OP(http://stackoverflow.com/questions/ 11073196/shallow-copy-of-custom-c-sharp-object)似乎在你的例子中使用完全相同的數據結構? –

回答

8

一個爲什麼你ResultList類不會與工作的原因Jon Skeet的example是因爲它沒有實現ICloneable接口。

在您需要克隆的所有類上實現ICloneable,例如,

public class ResultItem : ICloneable 
{ 
    public object Clone() 
    { 
    var item = new ResultItem 
       { 
        ID = ID, 
        Name = Name, 
        isLegit = isLegit 
       }; 
    return item; 
    } 
} 

而且還ResultList:

public class ResultList<T> : IEnumerable<T>, ICloneable where T : ICloneable 
{ 
    public List<T> Results { get; set; } 
    public decimal CenterLatitude { get; set; } 
    public decimal CenterLongitude { get; set; } 

    public object Clone() 
    { 
    var list = new ResultList<T> 
       { 
        CenterLatitude = CenterLatitude, 
        CenterLongitude = CenterLongitude, 
        Results = Results.Select(x => x.Clone()).Cast<T>().ToList() 
       }; 
    return list; 
    } 
} 

然後讓你的對象的深層副本:

resultList.clone(); 
+0

很好的解釋。非常感謝你的幫助。 – user70192

12

涉及最少編碼工作的方法是通過BinaryFormatter進行序列化和反序列化。

你可以定義下面的擴展方法(從Kilhoffer’s answer拍攝):

public static T DeepClone<T>(T obj) 
{ 
    using (var ms = new MemoryStream()) 
    { 
     var formatter = new BinaryFormatter(); 
     formatter.Serialize(ms, obj); 
     ms.Position = 0; 
     return (T)formatter.Deserialize(ms); 
    } 
} 

...然後只要致電:

ResultList<T> clone = DeepClone(original); 
1

這裏是什麼,我需要和寫的,它使用反射來複制每個財產(和私人的,如果指定的話)

public static class ObjectCloner 
{ 
    public static T Clone<T>(object obj, bool deep = false) where T : new() 
    { 
     if (!(obj is T)) 
     { 
      throw new Exception("Cloning object must match output type"); 
     } 

     return (T)Clone(obj, deep); 
    } 

    public static object Clone(object obj, bool deep) 
    { 
     if (obj == null) 
     { 
      return null; 
     } 

     Type objType = obj.GetType(); 

     if (objType.IsPrimitive || objType == typeof(string) || objType.GetConstructors().FirstOrDefault(x => x.GetParameters().Length == 0) == null) 
     { 
      return obj; 
     } 

     List<PropertyInfo> properties = objType.GetProperties().ToList(); 
     if (deep) 
     { 
      properties.AddRange(objType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic)); 
     } 

     object newObj = Activator.CreateInstance(objType); 

     foreach (var prop in properties) 
     { 
      if (prop.GetSetMethod() != null) 
      { 
       object propValue = prop.GetValue(obj, null); 
       object clone = Clone(propValue, deep); 
       prop.SetValue(newObj, clone, null); 
      } 
     } 

     return newObj; 
    } 
} 
+0

處理繼承對象列表:我只是創建第二個答案,因爲代碼在評論吸吮。 – jeromeyers

3

擴大對@格奧爾基 - 這,我不得不修改自己的代碼來處理其類型的屬性繼承列表:

public static class ObjectCloner { 
    public static T Clone<T>(object obj, bool deep = false) where T : new() { 
     if (!(obj is T)) { 
      throw new Exception("Cloning object must match output type"); 
     } 

     return (T)Clone(obj, deep); 
    } 

    public static object Clone(object obj, bool deep) { 
     if (obj == null) { 
      return null; 
     } 

     Type objType = obj.GetType(); 

     if (objType.IsPrimitive || objType == typeof(string) || objType.GetConstructors().FirstOrDefault(x => x.GetParameters().Length == 0) == null) { 
      return obj; 
     } 

     List<PropertyInfo> properties = objType.GetProperties().ToList(); 
     if (deep) { 
      properties.AddRange(objType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic)); 
     } 

     object newObj = Activator.CreateInstance(objType); 

     foreach (var prop in properties) { 
      if (prop.GetSetMethod() != null) { 
       var proceed = true; 
       if (obj is IList) { 
        var listType = obj.GetType().GetProperty("Item").PropertyType; 
        if (prop.PropertyType == listType) { 
         proceed = false; 
         foreach (var item in obj as IList) { 
          object clone = Clone(item, deep); 
          (newObj as IList).Add(clone);        
         }       
        }      
       } 

       if (proceed) { 
        object propValue = prop.GetValue(obj, null); 
        object clone = Clone(propValue, deep); 
        prop.SetValue(newObj, clone, null); 
       }     
      } 
     } 

     return newObj; 
    } 
}