2010-08-03 8 views
13

Estoy intentando a lo profundo del clon de la clase siguiente usando AutoMapper:Cómo objetos clon profundas que contienen una propiedad IList usando AutoMapper

public class MainData 
{ 
    public MainData() 
    { 
     Details = new List<Detail>(); 
    } 

    public int Id { get; private set; } 
    public DateTime LastUpdate { get; private set; } 
    public IList<Detail> Details { get; private set; } 
    public int Prop1 { get; set; } 
    public int Prop2 { get; set; } 

    public void AddDetail(Detail detail) 
    { 
     Details.Add(detail); 
    } 

    public void RemoveDetail(Detail detail) 
    { 
     Details.Remove(detail); 
    } 

    public MainData Clone() 
    { 
     Mapper.Reset(); 
     Mapper.CreateMap<MainData, MainData>().ForMember(d => d.Id, o => o.Ignore()); 
     // Mapper.CreateMap<Detail, Detail>().ForMember(d => d.Id, o => o.Ignore()); // REMOVED 
     var newMainData = new MainData(); 
     Mapper.Map(this, newMainData); 
     newMainData.Details = this.Details.Select(item => item.Clone()).ToList(); // ADDED 
     return newMainData; 
    } 
} 

public class Detail 
{ 
    public int Id { get; private set; } 
    public string Name { get; set; } 
    public double Area { get; set; } 
    public double Height { get; set; } 

    public Detail Clone() // ADDED 
    { 
     Mapper.CreateMap<Detail, Detail>().ForMember(d => d.Id, o => o.Ignore()); 
     var newDetail = new Detail(); 
     Mapper.Map(this, newDetail); 
     return newDetail; 
    } 
} 

El método Clone funciona bien para las propiedades MainData pero parece que sólo hacer una copia superficial de la lista de detalles. He intentado agregar .ForMember(d => d.Details, o => o.UseDestinationValue()), pero esto no copia la lista Detalles en absoluto. ¿Cómo puedo obtener la lista de detalles profundamente clonada también, es decir, así que termino con dos objetos totalmente independientes, incluidos todos los elementos de la lista?

ACTUALIZACIÓN: Necesito excluir la propiedad Id ya que estoy usando estos objetos con NHibernate, por lo que no estoy seguro si la solución Serializable lo hará.

UPDATE2: Modificó el código anterior para clonar el IList también. Esto parece funcionar bien ya que puedo excluir propiedades que hacen que NHibernate piense que ya se ha guardado.

Respuesta

9

aquí es una solución con los ValueInjecter

 var clone = new MainData(); 

     clone.InjectFrom(mainData);//mainData is your source 

     mainData.Details.AsParallel.ForAll(detail => 
     { 
      var dc = new Detail(); 
      dc.InjectFrom(detail); 
      clone.AddDetail(dc); 
     }); 

las propiedades que tienen los emisores privados no van a ajustar, (parece razonable)
buena suerte;)

EDIT: lo hice una mejor solución mira here

+0

Muy buena biblioteca, funciona bien. Tuve que cambiar la parte de PLINQ a un bucle de ForEach porque aún no estoy usando .NET 4. –

+0

@Piers Myers, hice algo más genérico para la clonación, puede verlo aquí http://valueinjecter.codeplex.com/wikipage?title=Deep%20Cloning&referringTitle=Home – Omu

+0

gracias por la actualización, lo verificaré. –

9

AutoMapper no es realmente una API de clonación. En su lugar, utilizaría este truco de clonación:

public static object CloneObject(object obj) 
{ 
    using (MemoryStream memStream = new MemoryStream()) 
    { 
     BinaryFormatter binaryFormatter = new BinaryFormatter(null, 
      new StreamingContext(StreamingContextStates.Clone)); 
     binaryFormatter.Serialize(memStream, obj); 
     memStream.Seek(0, SeekOrigin.Begin); 
     return binaryFormatter.Deserialize(memStream); 
    } 
} 

No funciona para todas las situaciones, pero es bastante útil.

+0

gracias, me encontré con esta solución un par de veces en mi búsqueda, pero no estaba seguro de querer hacer todas mis clases serializables. El método Automapper parecía bastante elegante si logro que funcione como yo quiero. –

+0

este es un truco popular para la clonación. desafortunadamente, presenta todo tipo de problemas que vienen con la serialización/deserialización. Esperaba que AutoMapper fuera más directo también :) –

Cuestiones relacionadas