2012-05-16 3 views
0

"SmallClass"라는 C# 클래스가 있습니다.딥 클론 c의 개체 목록

나는 유형 "SmallClass"

내가 목록 "으로 myList"의 깊은 복제를 원하는의 객체를 포함하고있는 기존 목록으로 myList 있습니다. 즉, 포함 된 목록을 복제하고 목록에 포함 된 개체를 깊이 복제합니다.

어떻게해야합니까?

public class SmallClass: ICloneable { 

    public string str1; 
    public string str2; 
    public string str3; 

    public SmallClass Clone() //This just deep clones 1 object of type "SmallClass" 
      { 
       MemoryStream m = new MemoryStream(); 
       BinaryFormatter b = new BinaryFormatter(); 
       b.Serialize(m, this); 
       m.Position = 0; 
       return (SRO)b.Deserialize(m); 
      } 

     public override equals(Object a) 
     { 
       return Object.Equals(this.str1 && a.str1); 
      } 
    } 

    public class AnotherClass 
    { 
      SomeCode(); 
      List<SmallClass> myList = new List<SmallList>(); //myList is initialized. 


      // NOW I want to deep clone myList. deep Clone the containing list and deep clone the objects contained in the list. 

     List<SmallClass> newList = new List<SmallClass>(); 
     foreach(var item in myList) 
     { 
      newList.Add((SmallClass)item.Clone()); 
     }  

은}

+0

여기 무슨 일이야? ' – climbage

답변

4

우선 해제, 당신은 깊은 복제 개체를 (루트)에 대한 유틸리티 메소드를 정의 할 수 있습니다 :

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

당신이 깊은 복제 myList하려는 경우, 당신이 할 필요가 건네입니다 위의 방법 매개 변수로 :

List<SmallClass> myListClone = DeepClone(myList); 

를 통해 일반적으로, 모든 클래스가 serializable로 표시해야한다는 것입니다에 당신이주의해야 할 가장 중요한 고려 사항.

[SerializableAttribute] 
public class SmallClass 
{ 
    // … 
} 
+0

ICloneable 인터페이스 클래스의 인터페이스 메소드 "Clone"- ICloneable에서 상속받는 경우 - DeepClone() 대신 "Clone"메서드를 호출합니다. – User1

+0

'BinaryFormatter'는 전체 개체 그래프를 깊이 복제합니다. Clone 메소드를 계속해서 호출하지 않아도됩니다. 유일한 제약 조건은 사용자 정의 클래스가'[SerializableAttribute]'로 표시되어야한다는 것입니다. – Douglas

+0

"DeepClone (myList)"를 호출하면 myList의 중첩 된 객체 참조를 자동으로 자세히 처리한다는 의미입니까? – User1

4

귀하의 SmallClass는 ICloneable 인터페이스를 구현해야합니다. 그런 다음 Clone() 메서드를 사용하여 모든 요소를 ​​복사합니다.

List<SmallClass> newList = new List<SmallClass>(); 
foreach(var item in myList) 
{ 
    newList.Add((SmallClass)item.Clone()); 
} 
+0

"SmallClass"의 ICloneable에서 상속받은 복제 구현을위한 새로운 구현을 제공해야합니까 – User1

+0

예, ICloneable은 구현이 없다는 것을 의미하는 인터페이스 일뿐입니다. 도대체 무엇이. Clone() 메서드를 직접 구현해야합니다. 이것이 내가 "인터페이스 구현"이라고 말한 것입니다. – BTownTKD

+0

확인. 내 원래 게시물에 제안을 추가합니다. 코드가 기능상으로 부족한 것 같습니까? SmallClass에는 클래스 멤버가 포함되어 있지 않습니다. 이러한 클래스를 복제 할 필요는 없습니다. – User1

0

직렬화를 포함하고 Object.MemberwiseClone Method()를 사용하여 전체 복사본을 만드는 방법에는 몇 가지가 있습니다. 직렬화를 사용하는 예제는 이미 여기에서 사용할 수 있으므로 "MemberwiseClone"을 사용하는 방법이 있습니다.

참고 : 재귀, 플랫폼 : .NETStandard2.0는

 /// <summary> 
     /// Returns a deep copy of an object. 
     /// </summary> 
     /// <typeparam name="T"></typeparam> 
     /// <param name="source"></param> 
     /// <returns></returns> 
     public static T DeepClone<T>(this T source) where T : class 
     { 
      if(source == null) return null; 

      if(source is ICollection<object> col) 
      { 
       return (T)DeepCloneCollection(col); 
      } 
      else if(source is IDictionary dict) 
      { 
       return (T)DeepCloneDictionary(dict); 
      } 

      MethodInfo method = typeof(object).GetMethod("MemberwiseClone", BindingFlags.NonPublic | BindingFlags.Instance); 
      T clone = (T)method.Invoke(source, null); 

      foreach(FieldInfo field in source.GetType().GetRuntimeFields()) 
      { 
       if(field.IsStatic) continue; 
       if(field.FieldType.GetTypeInfo().IsPrimitive) continue; 

       object sourceValue = field.GetValue(source); 
       field.SetValue(clone, DeepClone(sourceValue)); 
      } 

      return clone; 
     } 

     private static ICollection<object> DeepCloneCollection(ICollection<object> col) 
     { 
      object[] arry = (object[])Activator.CreateInstance(col.GetType(), new object[] { col.Count }); 

      for(int i = 0; i < col.Count; i++) 
      { 
       object orig = col.ElementAt(i); 
       object cln = DeepClone(orig); 

       arry[i] = cln; 
      } 

      return arry; 
     } 

     private static IDictionary DeepCloneDictionary(IDictionary dict) 
     { 
      IDictionary clone = (IDictionary)Activator.CreateInstance(dict.GetType()); 

      foreach(object pair in dict) 
      { 
       object key = pair.GetValueOf("Key"); 
       object original = pair.GetValueOf("Value"); 

       clone.Add(key, original.DeepClone()); 
      } 

      return clone; 
     } 

     public static dynamic GetValueOf<T>(this T value, string property) 
     { 
      PropertyInfo p = value.GetType().GetTypeInfo().GetProperty(property); 

      if(p != null && p.CanRead) 
      { 
       dynamic val = p.GetValue(value); 

       return val; 
      } 

      return Activator.CreateInstance(p.PropertyType); //Property does not have value, return default 
     }