2012-06-17 41 views
6

Sto lavorando su un codice scritto in C#. In questa app, ho una raccolta personalizzata definita come segue:Copia profonda di un oggetto C#

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

Il tipo utilizzato da Risultati è uno dei tre tipi personalizzati. Le proprietà di ciascuno dei tipi personalizzati sono solo tipi primitivi (int, stringhe, bool, int? Bool?). Ecco un esempio di uno dei tipi personalizzati:

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

Come faccio a eseguire una copia completa di un oggetto risultante che ho creato. Ho trovato questo post: Generic method to create deep copy of all elements in a collection. Tuttavia, non riesco a capire come farlo.

+0

Che cosa hai provato? Quale messaggio di errore hai ricevuto? Il codice di Jon Skeet che hai trovato funziona semplicemente per quanto posso vedere. –

+0

Copia poco profonda o profonda? http://stackoverflow.com/questions/11073196/shallow-copy-of-a-custom-c-sharp-object –

+0

Perché sei tu e l'OP di [questo queston] (http://stackoverflow.com/questions/ 11073196/shallow-copy-of-a-custom-c-sharp-object) sembra utilizzare la stessa struttura di dati esatta nell'esempio? –

risposta

8

Uno dei motivi per cui la classe risultante non funziona con example di Jon Skeet è perché non implementa l'interfaccia ICloneable.

Implementare ICloneable su tutte le classi che è necessario, per esempio clonati

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

E anche il risultante:

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

poi a fare una copia completa del vostro oggetto:

resultList.clone(); 
+0

Ottima spiegazione. Grazie mille per il vostro aiuto. – user70192

12

L'approccio che coinvolge il minimo sforzo di codifica è quello di serializzazione e deserializzazione attraverso un BinaryFormatter.

Si potrebbe definire il seguente metodo di estensione (tratto da 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); 
    } 
} 

... e poi basta chiamare:

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

Qui è qualcosa di cui avevo bisogno e ho scritto, si utilizza la reflection per copiare immobili ogni (e quelle private se specificato)

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

Gestisci oggetti che ereditano Elenco : creerò solo una seconda risposta poiché il codice nei commenti fa schifo. – jeromeyers

3

Ampliando @ Georgi-it, ho dovuto modificare il suo codice per gestire le proprietà il cui tipo eredita 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; 
    } 
} 
Problemi correlati