Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserializing properties into a pre-existing object

Is it possible to deserialize object properties, using any of the standard serializers, without creating a new object?

Problem is, the objects in question are very complex (they can only be created by a special factory, and their types are dynamically generated at runtime), but they have some known properties, which I would like to store in external file (preferably xml, but binary is OK too), and later (possibly after application is restarted), I want stored properties to be set back to the object I provide.

It seems all the standard serializers can only generate a new object for me (which also requires a public parameterless constructor), from which I would have to manually assign all the properties. This is not much different from manual serialization, which I would like to avoid, since a set of serialized properties is quite large and is probably going to change a few times during project lifetime. At this point I'm quite close to writing my own lightweight serializer, but maybe someone could suggest a more standard way of doing such things?

like image 315
Chriso Avatar asked Feb 26 '10 12:02

Chriso


2 Answers

protobuf-net has a Serializer.Merge method that lets you deserialize into an existing instance. Only values found in the stream are written (it doesn't wipe the object).

Not Microsoft, but pretty stable.

To expand on this; getting robust serialization that handles all the common scenarios is (I know from painful experience) a lot of work. My recommendation would definitely be to re-use existing code where possible. protobuf-net seems to offer everything you need; the current binaries simply require you to decorate your class (very similar to [DataContract] from WCF - in fact it even supports [DataContract] / [DataMember]), but work is in place to allow it to work even against POCO - so you can use it with types outside your control.

like image 184
Marc Gravell Avatar answered Nov 05 '22 22:11

Marc Gravell


You can use FormatterServices class.

You have a class Book:

[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;
    }
}

You can serialize it like this:

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);

If your object is modified:

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

You can restore it with the following code:

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);
like image 43
Maxence Avatar answered Nov 05 '22 22:11

Maxence