2009-05-07 10 views
12

Necesito guardar algunas clases y estructuras de datos en un archivo. Mi primer reflejo fue utilizar la serialización XML o binaria, pero esto se está convirtiendo en una pesadilla. Tengo un conjunto de clases que no estaban destinadas a ser serializadas (entidades privadas, constructores sin parámetros, sin atributos de serialización, diccionarios, etc.). Considerando que no puedo cambiar esas clases, ¿qué debería hacer? ¿Hay alguna solución y todavía se usa la serialización?¿Cómo serializar las clases que no fueron diseñadas para ser serializadas?

¿Tendré que escribir todo el código para escribir las propiedades, colecciones, etc.?

+0

buena pregunta, ¿puede explicar los requisitos de rendimiento y la escala del problema en cuestión? –

+0

En este punto, realmente no tengo ningún requisito. Estoy buscando la solución más elegante. – Martin

+1

realmente no se puede diseñar una solución a un problema de cero requisitos :) no importa qué solución elija, es probable que sea la solución incorrecta. Realmente no hay forma de responder a esto si no hay requisitos ... –

Respuesta

9

Utilice el JavaScriptSerializer. Está en el espacio de nombres System.Web.Script.Serialization y se implementa en el marco 3.5 en el ensamblado System.Web.Extensions.dll.

Con esta clase, puede serializar cualquier POCO si está marcado como [Serializable] o no. Su programa no tiene que ser una aplicación web para usar la serialización JSON.Aquí hay un ejemplo:

public class Unserializable 
{ 
    public int Age { get; set; } 
    public int ID { get; set; } 
    public string Name { get; set; } 
} 

public class Program 
{ 
    static void Main() 
    { 
    var u = new Unserializable 
      { 
       Age = 40, 
       ID = 2, 
       Name = "Betty" 
      }; 
    var jser = new JavaScriptSerializer(); 
    var jsonText = jser.Serialize(u); 
    // next line outputs {"Age":40,"ID":2,"Name":"Betty"} 
    Console.WriteLine(jsonText); 
    } 
} 
+0

+1 por lo que no sabía. ¿Esto maneja los campos también? –

+0

Sí, también maneja los campos. Pruebe esto: public class Unserializable { public int Age; public int ID {get; conjunto; } cadena pública Nombre {get; conjunto; } public Unserializable (int age, int id, string name) { Edad = edad; ID = id; Nombre = nombre; } } var u = new Unserializable (40, 2, "Donna"); var jser = new JavaScriptSerializer(); var jsonText = jser.Serialize (u); Console.WriteLine ("Serialized {0} using" + "JavaScriptSerializer en {1}:", u.GetType(). Name, jsonText); Esto genera texto JSON para el objeto que contiene el campo público como '{"Edad": 40, "ID": 2, "Nombre": "Donna"}'. –

0

me gustaría utilizar una herramienta de generación de código (MyGeneration, T4, lo que sea) para generar los dtos a serializar ...

+0

El problema con la generación de código para salir de esto es que si la clase cambia debe codificar gen de nuevo. Esto puede o no ser un problema. –

+0

No veo ningún motivo para -1 esto ... –

0
No

una solución simple.

Probablemente solo desee serializar/deserializar los campos (privados y públicos) en las clases, y hacerlo recursivamente. Probablemente necesites usar el reflejo para llegar a ellos. No de/serialice las propiedades, ya que podría haber efectos secundarios cuando establezca un valor de propiedad. También tendrás que recursivamente de/serializar todos los campos que son Objetos. El desafío es saber dónde parar.

Tendrá que hacer grandes suposiciones sobre cómo deserializar un objeto serializado mediante el reflejo. Tengo que suponer que algunos de los campos de esos objetos contienen referencias a otros objetos, y también tendrías que saber cómo atravesar todo eso.

Además, tendrá que llamar a los constructores parametrizados y esperar que no esté haciendo demasiado daño al configurar los campos con reflexión.

En resumen, puede que sea mejor que cree un conjunto de clases de contenedor de propósito especial que crea la mejor forma de volver a crear sus clases propietarias desde un formato serializado. Sus clases especiales podrían ser serializables. Esta no va a ser una tarea simple.

Dicho esto, código gen podría ser capaz de simplificar la tarea de identificar todos los campos en las clases.

0

Otra opción es utilizar un patrón de adaptador.

Una buena noticia es que no tendrá que cambiar la clase original. Las malas noticias son que probablemente termines escribiendo el doble de código que existe en la primera clase "inmutable".

Terminará con 2 nuevas clases: el adaptador y la nueva clase serializable.

La idea es que el adaptador sepa cómo crear la clase serizliable mediante el examen de la clase no serializable. Para ir por el otro lado (serializable a no serializable) puede volver a usar un adaptador (por supuesto, aquí estoy suponiendo que sus ajustadores privados se configuran realmente a través del constructor parametrizado).

Here's the pattern in detail.

0

Hay dos partes separadas a esto:

  1. extraer/ajustar los datos
  2. almacenamiento/lectura desde un archivo (u otro lugar)

Para el primera parte, si no puede cambiar las clases que desea serializar/deserializar, realmente le queda hacer una copia profunda a través de la reflexión.

Para la serialización, revise cada miembro de la clase almacenando su valor.

Utilice el medio en el que quiera almacenarlo, por ejemplo XML, y escriba estos valores en el disco.

Para la deserialización, lea los valores del archivo, cree una nueva instancia del objeto y use la reflexión para establecer todos los valores.

Si obtiene/establece todos los miembros, tendrá un objeto que se encuentra en un estado idéntico. (Es posible que deba examinar recursivamente todos sus objetos si tiene miembros complejos).

En cuanto a la forma de almacenar los datos en el disco, xml o binarios ambos funcionan. Si desea verlo y hacer que sea legible por humanos, entonces vaya con XML. (Recomendaría esto para su puñalada inicial, ya que hará que la depuración sea mucho más fácil.)

7

¡Suena como un trabajo para ... la serialización se sustituye!

Ir a http://msdn.microsoft.com/en-us/magazine/cc188950.aspx

para una visión general.

+0

+1: los sustitutos jugarán bien con BinaryFormatter. –

+0

Enlace muerto, archive aquí: https://web.archive.org/web/20141231105711/http://msdn.microsoft.com/en-us/magazine/cc188950.aspx, o MSDN: https: // msdn. microsoft.com/en-us/library/system.runtime.serialization.surrogateselector(v=vs.110).aspx –

0

Realmente depende de la escala de su problema y el rendimiento que necesita.

Si tiene 1 clase de problema, solo escribiría una clase sustituta que pueda serializar/deserializar esa clase. Si está hablando de cientos de clases, probablemente necesite utilizar un marco de serialización que admita todas las complejidades. Ninguna construcción sin parámetros es una pesadilla, cualquiera que sea el marco de serialización que escriba o use necesitará saber los params para pasarlos al constructor. Setters privados/diccionarios/listas, etc. no son un gran problema.

Escribí un marco mini-serialization para Media Browser que es BSD. Mi atención se centró en el rendimiento, pero las técnicas que uso se pueden adaptar a su problema. De forma similar, podrían usarse las técnicas utilizadas en Marc's protocol buffers.

Si el rendimiento no es importante en absoluto, un marco de serialización bastante trivial se puede codificar con bastante rapidez y utiliza la reflexión, las cosas se ponen difíciles cuando intenta mantener el rendimiento.

Cuestiones relacionadas