Jump to content
  • Advertisement
Sign in to follow this  
Hombert

[.net] Abandoning .net serialization?

This topic is 3830 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

A little while ago I got into a fight with .NET serialization and wound up abandoning it in favor of writing my own methods. The fact that it's a complete black box is one issue, as it makes finding serialization errors very tedious. The most important reason I chose not to use it is because of how it handles complex objects which implement ISerializable, holding other objects which also implement ISerializable. When evaluating the name/value pairs given to it by the serialization methods, it actually evaluates all of the pairs of the initial class, and THEN goes and evaluates the name/value pairs of the contained objects. Sorry if this doesn't make sense, in other words deserialization goes breadth first instead of depth first. The result of this is that deserialization code isn't run in the same order as it is written, which resulted in a lot of subtle problems. Interestingly, this doesn't happen if the class is simply marked as Serializable and doesn't implement ISerializable, but that isn't an option in my case. I might have been able to get around it using some callbacks or breaking the deserialization into parts or something, but I didn't want to bring that kind of complexity into my classes. What's done is done and it would take too much effort to go back to serialization, but there's always been this nagging suspicion that there's just one small bit of information that would have instantly solved my problem. "Oh, you just need to put the [Fnord] tag on your objects, then they will magically work the way you want!" Unfortunately all the material I can find on .net serialization is just basic examples of how to save a simple object, and nothing touches on the point I'm making here.

Share this post


Link to post
Share on other sites
Advertisement
Perhaps a little more of the context where you are using might help. I haven't directly dealt with serialization myself, but if we can know exactly what you are doing someone here who has experience might be able to lend a hand. Either that, or post a few source snippets.

Share this post


Link to post
Share on other sites
Hombert,

As of .Net 1.1 the ISerializable was the prefered way to handle complex serialization. When .Net 2.0 came out the suggested method moved to attribute based methods instead. The following shows some basics that I use (this is an example and excludes much of the actual class but the serialization basics):


[Serializable()]
public class ModelVertexMap
{

#region Variables

internal TextureMapProxy tmapProxy;
[NonSerialized()]
internal TextureMap tmap;

#endregion

#region Constructors / Destructor

/// <summary>
/// Used for serialization.
/// </summary>
public ModelVertexMap()
{
}

#endregion

#region Serialization/Deserialization

/// <summary>
/// Fires after de-serialization has occured.
/// </summary>
/// <param name="context">Any context data sent to the object being de-serialized.</param>
[OnDeserialized()]
private void Deserialize(System.Runtime.Serialization.StreamingContext context)
{
this.deserializing = true;
Platform.PlatformContext pc = context.Context as Platform.PlatformContext;
if (pc != null)
{
if (this.tmapProxy != null)
{
this.TextureMap = (pc.Platform as IModelEngine).TextureEngines.FindVertexMap(this.tmapProxy);
}
}
else throw new SerializationException("Invalid context object PlatformContext in VertexMap, Context object cannot be null!");
this.deserializing = false;
}

/// <summary>
/// Fires before serialization occures.
/// </summary>
/// <param name="context">Any context data that needs to be sent to the object being serialized.</param>
[OnSerializing()]
private void Serialize(System.Runtime.Serialization.StreamingContext context)
{
/*Serialize a proxy for the texture map only since the maps and engines can be arranged in
* a different sequence later on when this object is loaded again. The TextureMap's
* name and Engine name will need to be used to find the TextureMap assigned to it
* currently. Thus the need for a proxy that stores only this information.
*/

if (this.tmap != null) this.tmapProxy = new TextureMapProxy(this.tmap);
}

#endregion

}




As you can see you can mark methods with attributes that are called during the serialization process that are supplied with the context and serialization data. You can supply your own custom context objects that are needed during the serialization process as well.

Check out the attributes in the Serialization namespace there are ones that fire at various points during the process.

HTH,

-Devin

Share this post


Link to post
Share on other sites
The next time I make a project I think I'll go that route. The problem is that all the resources I've found on Serialization never mentioned that methods can be tagged. That isn't something new, is it? Everything I see just suggests using ISerializable.

My own serialization process isn't so bad, it uses .net serialization for the parts that it can work for and its less work to serialize an object at the class level (at the expense of having to write my own serialization engine but that wasn't so bad). In the future I'll go the attribute route though.

Share this post


Link to post
Share on other sites
I haven't worked TOO much with .NET serialization so far, but it does seem pretty nice. It does take some wading through the options (want XML or binary output? implement ISerializable or use attributes?) to figure out the technique.

That said, I have been using the attributes technique to serialize an object graph to XML and bring it back again. Outside of the classes involved, it just takes a few lines of code to kick off the de/serialization process.

True, you could write your own de/serialization functionality, but why not use what's in place already? I used to do the above work in the old way, manually reading and writing XML files, but when I discovered /NET serialization I was able to eliminate quite a lot of extraneous code.

Share this post


Link to post
Share on other sites
Quote:

True, you could write your own de/serialization functionality, but why not use what's in place already?

Well, there are occasionally valid reasons -- I manually(*) serialize my asset classes, for example, because the .NET serialization is quite verbose and not exactly easy to restore manually (e.g., from native C++ code).

(*) Rather, of course, my asset tool generates me code to serialize them manually.

Share this post


Link to post
Share on other sites
I've written my own code for it, which serializes it to a REALLY ugly XML format. All my classes implents ISavable, which has the methods required. If I try to serialize an object which doesn't implent ISavable, it instead uses BinaryFormatter for that object, and saves it to the XML file with base64 encoding.

The reason for this is that BinaryFormatter sometimes have problems with objects that change from serialization to deserialization. This happens quite often in my development process. Implenting ISerializable didn't help.

Share this post


Link to post
Share on other sites
Quote:
Original post by HombertThe problem is that all the resources I've found on Serialization never mentioned that methods can be tagged.


You mean fields instead of methods? Fields can be tagged as non-serialized.

There is some weird decisions made in the serialization classes provided. The XML serializer will only serialize public read/write properties (and maybe fields?), so if you have private data you want serialized, that's out unless you want implement IXmlSerializable and do your own XML parsing. Then there's the Soap formatter, which gives nice XML output, but fails if its asked to serialize any generic container. I'd really like to have a formatter that will serialize my objects to human-readable XML, and can handle generic containers and deal with private fields.

I've often wondered how much work it would be to implement the IFormatter interface myself to write a formatter that does what I want. But I've never tried or done any research on how to do it. But if you don't like the way BinaryFormatter works, you might consider using this as an option instead of throwing away everything in the System.Runtime.Serialization namespace. If you ever do something like that, I'd be interested to hear about it.

Share this post


Link to post
Share on other sites
Search for XmlFormatter. I think it's pretty good, but missing something making it unusable for me. Perhaps it can be extended to handle it though?

Share this post


Link to post
Share on other sites
Quote:
Original post by kanato
There is some weird decisions made in the serialization classes provided. The XML serializer will only serialize public read/write properties (and maybe fields?), so if you have private data you want serialized, that's out unless you want implement IXmlSerializable and do your own XML parsing. Then there's the Soap formatter, which gives nice XML output, but fails if its asked to serialize any generic container. I'd really like to have a formatter that will serialize my objects to human-readable XML, and can handle generic containers and deal with private fields.
Windows Communication Foundation can serialize public/private fields and properties, as well as generic types. It also supports serialization of types marked with the Serializable attribute. See this page for more information.

Of course, it's yet another serialization library to learn and requires .NET 3.0, but I've found it to be pretty easy so far. Here's a simple example:

[DataContract] // Indicates a type serializable by DataContractSerializer.
class Person
{
[DataMember]
public Name { get { return _name; } set { _name = value; } }

[DataMember]
private int _id;

[DataMember]
private List<Pet> Pets;

[DataMember]
private Uri _uri; // Uri has Serializable attribute

private string _name;
}

DataContractSerializer serializer = new DataContractSerializer(typeof(Person));

Stream stream;
serializer.WriteObject(stream, new Person());

Person p = (Person)serializer.ReadObject(stream);

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!