2009-08-09 11 views
10

Necesito realizar una clonación profunda en mi modelo de objeto complejo. ¿Cuál crees que es la mejor manera de hacerlo en .Net?
Pensé en serializar/deserializar
sin necesidad de mencionar que MemberwiseClone no es suficiente..Net Deep cloning: ¿cuál es la mejor manera de hacerlo?

+4

Tenga mucho cuidado; ¿Es esto lo que realmente quieres decir? Las referencias circulares entre objetos pueden causar problemas rápidamente con la clonación profunda. –

+0

esto lo hace sin serialización http://valueinjecter.codeplex.com/wikipage?title=Deep%20Cloning&referringTitle=Home – Omu

+0

UltraMapper https://www.nuget.org/packages/UltraMapper/ – sam

Respuesta

0

La mejor manera es probablemente implementar la interfaz System.IClonable en su objeto y todos sus campos que también necesitan capacidades personalizadas de clonación profunda. Luego implementa el método Clone para devolver una copia profunda de su objeto y sus miembros.

+2

Todavía hay recomendaciones en contra de esto, y Estoy de acuerdo con ellas.Lo razonable en un objeto puede significar profundo, mientras que en otro es superficial. No hay forma de discernir cuando se realiza una llamada. Por supuesto, esto no es completamente aplicable a un proyecto interno, pero no es una mala práctica reconocer temprano. – jfsk3

+0

IClonable no funciona para objetos complejos. –

13

Si controla el modelo de objetos, puede escribir el código para hacerlo, pero es mucho mantenimiento. Sin embargo, hay muchos problemas, lo que significa que, a menos que necesite absolutamente el rendimiento más rápido, la serialización suele ser la respuesta más manejable.

Este es uno de los casos en que BinaryFormatter funciona aceptablemente; normalmente no soy seguidor (debido a problemas con el control de versiones, etc.), pero dado que los datos serializados son de consumo inmediato, esto no es un problema.

Si lo desea un poco más rápido (pero sin su propio código), entonces protobuf-net puede ayudar, pero requiere cambios de código (para agregar los metadatos necesarios, etc.). Y está basado en un árbol (no basado en gráficos).

Otros serializadores (XmlSerializer, DataContractSerializer) también están muy bien, pero si es simplemente para el clon, es posible que no ofrecen mucho más BinaryFormatter (excepto, quizás, que no necesita XmlSerializer[Serializable].

Así que en realidad, que depende de sus clases exactas y el escenario.

+0

Quizás un enlace al ejemplo sea agradable. Estoy usando UWP y no puedo usar BinaryFormatter. El serializador XML está dado a continuación por Marty. Tengo curiosidad sobre DataContractSerializer y protobuf-net. –

0

usted podría intentar AltSerialize que en muchos casos es más rápido que el serializador .Net. también proporciona almacenamiento en caché y atributos personalizados para acelerar la serialización.

5

Ejemplo de clonación profunda de la revista MSDN:

Object DeepClone(Object original) 
    { 
     // Construct a temporary memory stream 
     MemoryStream stream = new MemoryStream(); 

     // Construct a serialization formatter that does all the hard work 
     BinaryFormatter formatter = new BinaryFormatter(); 

     // This line is explained in the "Streaming Contexts" section 
     formatter.Context = new StreamingContext(StreamingContextStates.Clone); 

     // Serialize the object graph into the memory stream 
     formatter.Serialize(stream, original); 

     // Seek back to the start of the memory stream before deserializing 
     stream.Position = 0; 

     // Deserialize the graph into a new set of objects 
     // and return the root of the graph (deep copy) to the caller 
     return (formatter.Deserialize(stream)); 
    } 
8

Si está ejecutando código en un entorno de confianza parcial, como la nube de Rackspace es probable que se restringe el uso de la BinaryFormatter. El XmlSerializer se puede usar en su lugar.

public static T DeepClone<T>(T obj) 
{ 
    using (var ms = new MemoryStream()) 
    { 
     XmlSerializer xs = new XmlSerializer(typeof(T)); 
     xs.Serialize(ms, obj); 
     ms.Position = 0; 

     return (T)xs.Deserialize(ms); 
    } 
} 
+0

No funciona cuando algunas propiedades del objeto clonado son interfaces (por ejemplo, IEnumerable, IList, etc.). Lanza una excepción. –

0

La mejor manera de implementar esto manualmente. Será realmente más rápido que cualquier otro método genérico. Además, hay muchas bibliotecas para esta operación (Puede ver una lista con los parámetros de rendimiento here).

Por cierto, BinaryFormatter es muy lento para esta tarea y puede ser bueno solo para las pruebas.

Cuestiones relacionadas