2010-02-26 25 views
5

¿Es posible deserializar las propiedades del objeto, utilizando cualquiera de los serializadores estándar, sin crear un objeto nuevo?Deserializar propiedades en un objeto preexistente

El problema es que los objetos en cuestión son muy complejos (solo pueden ser creados por una fábrica especial, y sus tipos se generan dinámicamente en tiempo de ejecución), pero tienen algunas propiedades conocidas, que me gustaría almacenar en externos archivo (preferiblemente xml, pero el binario también está bien), y más tarde (posiblemente después de que se reinicie la aplicación), quiero que las propiedades almacenadas se vuelvan a establecer en el objeto que proporciono.

Parece que todos los serializadores estándar solo pueden generar un nuevo objeto para mí (que también requiere un constructor público sin parámetros), desde el cual tendría que asignar manualmente todas las propiedades. Esto no es muy diferente de la serialización manual, lo cual me gustaría evitar, ya que un conjunto de propiedades serializadas es bastante grande y probablemente cambie varias veces durante la vida útil del proyecto. En este momento estoy bastante cerca de escribir mi propio serializador liviano, pero ¿alguien podría sugerir una forma más estándar de hacer tales cosas?

Respuesta

3

tiene un método Serializer.Merge que le permite deserializar en una instancia existente. Solo se escriben los valores encontrados en la secuencia (no borra el objeto).

No es Microsoft, pero es bastante estable.

Para ampliar esto; obtener una sólida serialización que maneje todos los escenarios comunes es (lo sé por experiencia dolorosa) mucho trabajo. Mi recomendación sería, definitivamente, reutilizar el código existente cuando sea posible. protobuf-net parece ofrecer todo lo que necesita; los binarios actuales simplemente requieren que decores tu clase (muy similar al [DataContract] de WCF, de hecho incluso admite [DataContract]/[DataMember]), pero el trabajo está en su lugar para permitir que funcione incluso contra POCO, por lo que puedes usarlo con tipos externos tu control.

+0

¿Eso no funciona en el nivel de campo, en lugar del nivel de propiedad como se solicita? – Lucero

+0

@Lucero - funciona en ambos campos y propiedades; depende de lo que le digas que haga. –

+0

Gracias por un enlace interesante, pero preferiría no involucrar un componente de terceros completamente nuevo para una tarea tan simple. También el inconveniente es que no es xml. – Chriso

0

Puede implementar su propio "serializador" flexible para manejar esto. Reflection te proporciona todo lo que necesitas.

0

se puede utilizar el método de FormatterServices.PopulateObjectMembers, que parece estar diseñado exactamente para esta tarea ...

+1

En ese punto, ya habrá tenido que analizar la secuencia para obtener los valores en 'object' s, * y * obtuvo los' MemberInfo's, * y * se ocupó de todas las complejidades de los subdatos, etc.Para ser honesto, simplemente tener un método para * establecer * los valores ofrece poco, en ese punto podría simplemente usar el reflejo. –

2

Puede utilizar FormatterServices clase.

usted tiene un libro de clase:

[Serializable] 
class Book 
{ 
    public string Title { get; set; } 

    public string Author { get; set; } 

    // Constructor for setting new values. 
    public Book(string title, string author) 
    { 
     Title = title; 
     Author = author; 
    } 
} 

puede serializar así:

var book = new Book("Moby Dick", "Herman Melville"); 

string path = Path.GetTempFileName(); 

var bf = new BinaryFormatter(); 
using (var fs = new FileStream(path, FileMode.Create)) 
    bf.Serialize(fs, book); 

Si se modifica el objeto:

// Edit object 
book.Title = "Foo"; 
Console.WriteLine("{0}, {1}", book.Title, book.Author); 

se puede restaurar con el código siguiente:

Book temp; 
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read)) 
    temp = (Book) bf.Deserialize(fs); 

MemberInfo[] members = FormatterServices.GetSerializableMembers(typeof (Book)); 
FormatterServices.PopulateObjectMembers(book, members, FormatterServices.GetObjectData(temp, members)); 

// Object state is back 
Console.WriteLine("{0}, {1}", book.Title, book.Author); 
Cuestiones relacionadas