2010-12-28 12 views
12

Estoy intentando crear un clon profundo de un objeto utilizando el siguiente método.diferencia entre el atributo DataContract y el atributo Serializable en .net

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

Este método requiere un objeto que se serializa es decir, un objeto de una clase que está teniendo un atributo "Serializable" en él. Tengo una clase que tiene el atributo "DataContract" pero el método no funciona con este atributo. Creo que "DataContract" también es un tipo de serializador pero quizás diferente de "Serializable".

¿Alguien puede darme la diferencia entre los dos? Además, avíseme si es posible crear un clúster profundo de un objeto con solo 1 atributo que haga el trabajo de los atributos "DataContract" y "Serializable" o una forma diferente de crear un deepclone.

Por favor ayuda!

Respuesta

23

Serializable es necesario para que BinaryFormatter funcione.

DataContract y el atributo DataMember se usan con el DataContractSerializer.

Puede decorar una clase con atributos para ambos serializadores.

+0

Gracias por la respuesta @Oded. Solo una pregunta aquí. Esta clase se está utilizando en mi Servicio WCF. Estoy consumiendo este servicio en mi proyecto de consumidor agregando la referencia de servicio del servicio. Siempre que haya un cambio en el Servicio, necesito actualizar la referencia del servicio. Cuando uso los atributos y luego actualizo el servicio, .net crea 2 propiedades con el mismo nombre en la clase Reference.cs de la Referencia del servicio. 1 cada uno para el atributo "DataMember" y "Serializable". Esto crea un error de compilación. ¿Algún trabajo para esto? – samar

+0

@samar - Hasta donde sé, 'Serializable' se ignorará si se usa' DataContract'. Nunca he oído hablar del problema que tienes. – Oded

5

DataContract se usa en WCF, por lo tanto .NET 3.0+. En .net 2.0 o inferior, no existe el atributo DataContract, DataMember, solo Serializable.

Como dijo Oded, si quieres usar BinaryFormatter tienes que decorar el tipo con Serializable.

2

Una vez realicé algunas inspecciones a una estructura de objetos a través de Reflection para encontrar todos los ensamblajes necesarios para la deserialización y serializarlos al costado para el arranque.

Con un poco de trabajo uno podría construir un método similar para la copia profunda. Básicamente, necesita un método recursivo que incluya un diccionario para detectar referencias circulares. Dentro del método de inspeccionar todos los campos más o menos así:

private void InspectRecursively(object input, 
    Dictionary<object, bool> processedObjects) 
{ 
    if ((input != null) && !processedObjects.ContainsKey(input)) 
    { 
    processedObjects.Add(input, true); 

    List<FieldInfo> fields = type.GetFields(BindingFlags.Instance | 
     BindingFlags.Public | BindingFlags.NonPublic); 
    foreach (FieldInfo field in fields) 
    { 
     object nextInput = field.GetValue(input); 

     if (nextInput is System.Collections.IEnumerable) 
     { 
     System.Collections.IEnumerator enumerator = (nextInput as 
      System.Collections.IEnumerable).GetEnumerator(); 

     while (enumerator.MoveNext()) 
     { 
      InspectRecursively(enumerator.Current, processedObjects); 
     } 
     } 
     else 
     { 
     InspectRecursively(nextInput, processedObjects); 
     } 
    } 
    } 
} 

para que funcione es necesario agregar un objeto de salida y algo así como System.Runtime.Serialization.FormatterServices.GetUninitializedObject(Type type) para crear la copia más somera (incluso sin copiar referencias) del valor de cada campo. Finalmente, puede definir cada campo con algo como field.SetValue(input, output)

Sin embargo, esta aplicación no es compatible con los gestores registrados evento, que es la ONU _ _supported por deserializar, también. Además, cada objeto en la jerarquía se romperá, si el constructor de su clase necesita inicializar cualquier cosa que no sea configurar todos los campos. El último punto solo funciona con la serialización, si la clase tiene una implementación respectiva, p. método marcado [OnDeserialized], implementa ISerializable, ....

Cuestiones relacionadas