2012-06-17 13 views
6

Tôi đang làm việc trên một số mã được viết bằng C#. Trong ứng dụng này, tôi có một bộ sưu tập tùy chỉnh được xác định như sau:Bản sao sâu của đối tượng C#

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

Loại được sử dụng bởi Kết quả là một trong ba loại tùy chỉnh. Các thuộc tính của mỗi kiểu tùy chỉnh chỉ là các kiểu nguyên thủy (ints, strings, bools, int ?, bool?). Dưới đây là một ví dụ về một trong những loại tùy chỉnh:

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

Làm thế nào để thực hiện một bản sao sâu sắc về một đối tượng ResultList mà tôi đã tạo ra. Tôi đã tìm thấy bài đăng này: Generic method to create deep copy of all elements in a collection. Tuy nhiên, tôi không thể tìm ra cách để làm điều đó.

+0

Bạn đã thử gì? Bạn nhận được thông báo lỗi nào? Mã của Jon Skeet mà bạn thấy đơn giản là hoạt động theo như tôi thấy. –

+0

Bản sao nông hoặc sâu? http://stackoverflow.com/questions/11073196/shallow-copy-of-a-custom-c-sharp-object –

+0

Tại sao bạn và OP của [nhiệm vụ này] (http://stackoverflow.com/questions/ 11073196/nông-copy-of-a-custom-c-sắc nét-đối tượng) dường như sử dụng chính xác cấu trúc dữ liệu giống nhau trong ví dụ của bạn? –

Trả lời

8

Một trong những lý do tại sao lớp ResultList của bạn sẽ không làm việc với Jon Skeet's example là bởi vì nó không thực hiện giao diện ICloneable.

Triển khai ICloneable trên tất cả các lớp mà bạn cần nhân bản, ví dụ:

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

Và cũng trên 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; 
    } 
} 

Sau đó, để tạo một bản sao sâu sắc về đối tượng của bạn:

resultList.clone(); 
+0

Giải thích tuyệt vời. Cảm ơn rất nhiều vì sự giúp đỡ của bạn. – user70192

12

Cách tiếp cận liên quan đến nỗ lực mã hóa ít nhất là việc nối tiếp và deserializing thông qua BinaryFormatter.

Bạn có thể xác định các phương pháp sau đây phần mở rộng (lấy từ 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); 
    } 
} 

... và sau đó chỉ cần gọi:

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

Đây là điều mà tôi cần và viết, nó sử dụng phản ánh để sao chép mọi thuộc tính (và các thuộc tính riêng nếu được chỉ định)

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

Xử lý các đối tượng kế thừa Danh sách : Tôi sẽ chỉ tạo câu trả lời thứ hai kể từ khi mã trong chú thích hút. – jeromeyers

3

Mở rộng trên @ Georgi-it, tôi phải sửa đổi mã của mình để xử lý các thuộc tính có loại thừa kế Danh sách:

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; 
    } 
}