2012-06-17 17 views
6

Ich arbeite an Code, der in C# geschrieben wird. In dieser App habe ich eine benutzerdefinierte Sammlung wie folgt definiert:Deep Copy eines C# -Objekts

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

Der Typ von Results sind eine von drei benutzerdefinierten Typen. Die Eigenschaften von jedem der benutzerdefinierten Typen sind nur primitive Typen (Ints, Strings, Bools, Int ?, Bool?). Hier ist ein Beispiel für eine der benutzerdefinierten Typen:

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

Wie kann ich eine tiefe Kopie eines Result Objekt durchführen, die ich angelegt habe. Ich habe diesen Beitrag gefunden: Generic method to create deep copy of all elements in a collection. Ich kann jedoch nicht herausfinden, wie es geht.

+0

Was haben Sie versucht? Welche Fehlermeldung haben Sie erhalten? Jon Skeets Code, den du gefunden hast, funktioniert soweit ich sehen kann. –

+0

Flache oder tiefe Kopie? http://stackoverflow.com/questions/11073196/shalllow-copy-of-a-custom-c-sharp-object –

+0

Warum bist du und das OP von [dieser Frage] (http://stackoverflow.com/questions/ 11073196/shallow-copy-of-a-custom-c-sharp-objekt) scheint in Ihrem Beispiel die exakt gleiche Datenstruktur zu verwenden? –

Antwort

8

Einer der Gründe, warum Ihre Result Klasse mit nicht funktionieren Jon Skeets example ist, weil es die ICloneable-Schnittstelle nicht implementiert.

Implementierung von ICloneable für alle Klassen, die geklont werden müssen, z.

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

Und auch auf Result:

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

Dann eine tiefe Kopie des Objekts zu machen:

resultList.clone(); 
+0

Große Erklärung. Vielen Dank für deine Hilfe. – user70192

12

Der Ansatz mit dem geringsten Programmieraufwand besteht in der Serialisierung und Deserialisierung über eine BinaryFormatter.

Sie konnten die folgende Erweiterungsmethode (aus Kilhoffer’s answer) definieren:

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

... und dann rufen Sie einfach:

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

Hier ist etwas, das ich brauchte, und schrieb, es verwendet Reflektion zu kopieren Jede Eigenschaft (und private, wenn angegeben)

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

Handle Objekte, die erben Liste : Ich werde nur eine zweite Antwort erstellen, da Code in den Kommentaren saugen. – jeromeyers

3

Aufbauend auf @ Georgi-it, hatte ich seinen Code ändern Eigenschaften, deren Art zu handhaben erbt List:

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