4

I often find myself in a quandary in where to put serialisation code for a class, and was wondering what others' thoughts on the subject were.

Bog standard serialisation is a no brainer. Just decorate the class in question.

My question is more for classes that get serialised over a variety of protocols or to different formats and require some thought/optimisation to the process rather than just blindly serialising decorated properties.

I often feel it's cleaner to keep all code to do with one format in its own class. It also allows you to add more formats just by adding a new class. eg.

class MyClass
{
}

Class JSONWriter
{
    public void Save(MyClass o);
    public MyClass Load();
}

Class BinaryWriter
{
    public void Save(MyClass o);
    public MyClass Load();
}

Class DataBaseSerialiser 
{
    public void Save(MyClass o);
    public MyClass Load();
}

//etc

However, this often means that MyClass has to expose a lot more of its internals to the outside world in order for other classes to serialise effectively. This feels wrong, and goes against encapsulation. There are ways around it. eg in C++ you could make the serialiser a friend, or in C# you could expose certain members as an explicit interface, but it still doesn't feel great.

The other option of course, is to have MyClass know how to serialize itself to/from various formats:

class MyClass
{
    public void LoadFromJSON(Stream stream);
    public void LoadFromBinary(Stream stream);

    public void SaveToJSON(Stream stream);
    public void SaveToBinary(Stream stream);
    //etc
}

This feels more encapsulated and correct, but it couples the formatting to the object. What if some external class knows how to serialise more efficiently because of some context that MyClass doesn't know about? (Maybe a whole bunch of MyClass objects are referencing the same internal object, so an external serialiser could optimise by only serialising that once). Additionally if you want a new format, you have to add support in all your objects, rather than just writing a new class.

Any thoughts? Personally I have used both methods depending on the exact needs of the project, but I just wondered if anyone had some strong reasons for or against a particular method?

GazTheDestroyer
  • 20,722
  • 9
  • 70
  • 103

2 Answers2

2

The most flexible pattern is to keep the objects lightweight and use separate classes for specific types of serialization.

Imagine the situation if you were required to add another 3 types of data serialization. Your classes would become quickly bloated with code they do not care about. "Objects should not know how they are consumed"

iCollect.it Ltd
  • 92,391
  • 25
  • 181
  • 202
  • 1
    I do pretty much agree, I tend to use external classes. However, serialisation often deals with the "guts" of an object that encapsulation says should not be known about by external classes. I do not like having to expose some of the guts. – GazTheDestroyer Nov 11 '11 at 10:56
  • 1
    @Gaz - I would argue that specialized actions for serialization/deserialization, due to internal the structure of the type, are governed by the type itself, not on the specific type of serialization required by some external consumer and, as such, should be implemented on the type itself using a custom ISerializable implementation and/or members attributed with OnDeserializing, OnDeserialized, OnSerializing, OnSerialized, NonSerialized etc. The actual serialization itself is still a concern external to the type and should therefore be performed by external types, as per the SRP priniciple. – Adam Ralph Nov 11 '11 at 11:06
  • That's a good description of my ambiguity, but you define the separation well. What you describe sounds pretty much like my first option, but with good justification for the exposing of guts as a special thing (ISerializable, friend class, other explicit interface whatever). You've clarified my thinking. Thanks. – GazTheDestroyer Nov 11 '11 at 12:15
  • @GazTheDestroyer: You first comment implies generic serialization, but you can always provide specific serialization classes that know about your data types and only those data types. Then "exposing the guts" is less of a problem. Shame sometimes that C# has no friend keyword. – iCollect.it Ltd Nov 11 '11 at 13:45
2

I guess it really depends on the context in which serialization will be used and also on limitations of systems using it. For example due to Silverlight reflection limitations some class properties need to be exposed in order for serializers to work. Another one, WCF serializers require you to know possible runtime types ad-hoc.

Apart from what you pointed out, putting serialization logic into the class violates SRP. Why would a class need to know how to "translate" itself to another format?

Different solutions are required in different situations, but I've mostly seen separated serializers classes doing the work. Sure it required exposing some parts of class internals, but in some cases you'll have to do it anyways.

k.m
  • 30,794
  • 10
  • 62
  • 86