Custom serialisation the .NET way, fully customised serialisation, just marking classes, and just marking classes and adding a few tweaks are all available:
Custom serialisation is useful when:
- An object is fully or partially immutable (one or more members is
readonly
) and hence must be deserialised via a constructor anyway (a factory method can also work by calling an existing constructor of course).
- A graph is complex, but much of it can be simplified with knowledge of the system (e.g. "I know I don't need to fully serialise that member I can just serialise enough information to create a new instance on deserialisation".
- A general-purpose class is used in a specific way (well, they always are...) and knowledge of those specifics can reduce the complexity of the graph.
- You are doing an XMLSeriazation of a class which inherits or implements a template class or abstract parameterised by itself (this goes into an infinite loop when mapping the graph, at least on
IEnumerable<T>
, I don't know if it happens for all such interfaces and I'm pretty sure it doesn't happen for binary serialisation - really it's a bug and should be fixed, but for the time being its there).
- You need to guarantee backwards and/or forwards compatibility with later versions of the class (up to you to make sure that works, but you've no hope if you aren't "in there").
- You have a member of a class that you can't edit (framework or third-part provided) that is not serialisable, so you need to provide your own method of serialising it.
ISerialisable will provide an abstraction (named things go in, named things come out) which is used in turn for different formats.
If you need a very specific format (e.g serialised in a particular pattern) then you may need to look at the other interfaces (e.g. IXmlSerializable) at being more explicit in use of the serialisation methods, or at ignoring .NET-provided serialisation techniques and rolling your own means to produce and parse the different formats.
At the other extreme, you can just put the [Serializable]
attribute on the class and any class that it has a member of and that will give you default serialisation behaviour.
Further tweaks can come from putting [NonSerialized]
on members that shouldn't be serialised (say you have BigObject _big; int _bigID
and memoise access to _big
by lazy-loading it based on _bigID
on first access. In this case you can serialise just _bigID
by marking _big
as non-serialised. IDeserializationCallback
allows further tweaks by informing your class when it has just been created by deserialisation.