What is the point of the ISerializable interface?
It seems like I can serialize classes that don't have that interface, so I am unclear on its purpose.
ISerializable
is used to provide custom binary serialization, usually for BinaryFormatter
(and perhaps for remoting purposes). Without it, it uses the fields, which can be:
- inefficient; if there are fields that are only used for efficiency at runtime, but can be removed for serialization (for example, a dictionary may look different when serialized)
- inefficient; as even for fields that are needed it needs to include a lot of additional metadata
- invalid; if there are fields that cannot be serialized (such as event delegates, although they can be marked
[NonSerialized]
) - brittle; your serialization is now bound to the field names - but fields are meant to be an implementation detail; see also Obfuscation, serialization and automatically implemented properties
By implementing ISerializable
you can provide your own binary serialization mechanism. Note that the xml equivalent of this is IXmlSerializable
, as used by XmlSerializer
etc.
For DTO purposes, BinaryFormatter
should be avoided - things like xml (via XmlSerializer
or DataContractSerializer
) or json are good, as are cross-platform formats like protocol buffers.
For completeness, protobuf-net does include hooks for ISerializable
(allowing you to use a portable binary format without writing lots of code), but BinaryFormatter
wouldn't be your first choice here anyway.
Classes can be serialized in .NET in one of two ways:
- Marking the class with
SerializableAttribute
and decorating all the fields that you don't want to be serialized with theNonSerialized
attribute. (As Marc Gravell points out,BinaryFormatter
, which is the class typically used to formatISerializable
objects, automatically serializes all fields unless they are specifically marked otherwise.) - Implementing the
ISerializable
interface for fully custom serialization.
The former is simpler to use as it simply involves marking declarations with attributes, but is limited in its power. The latter allows more flexibility but takes significantly more effort to implement. Which one you should use depends completely on the context.
Regarding the latter (ISerializable
) and it usage, I've quoted from the MSDN page for the interface:
Any class that might be serialized must be marked with the SerializableAttribute. If a class needs to control its serialization process, it can implement the ISerializable interface. The Formatter calls the GetObjectData at serialization time and populates the supplied SerializationInfo with all the data required to represent the object. The Formatter creates a SerializationInfo with the type of the object in the graph. Objects that need to send proxies for themselves can use the FullTypeName and AssemblyName methods on SerializationInfo to change the transmitted information.
In the case of class inheritance, it is possible to serialize a class that derives from a base class that implements ISerializable. In this case, the derived class should call the base class implementation of GetObjectData inside its implementation of GetObjectData. Otherwise, the data from the base class will not be serialized.
With the ISerializable
you can write custom methods in your object to take over serialization when doing binary serialization, to serialize your objects in a different manner than what the default approach used by BinaryFormatter will do.
In other words, if the default approach serializes your object in a different manner than how you want it to serialize as, you can implement ISerializable for complete control. Note that hand in hand with ISerializable, there's also a custom constructor you should implement.
XmlSerialization will of course only use properties, ISerializable has nothing to do with XML serialization.
Thanks Marc and Pop for the comments, I was a bit hasty with my first answer.
In order to make an object "transportable", you have to serialize it. For example, if you want to transfer object data using .NET Remoting or Web Services you have to provide methods which serializes your object data, reducing your object instances into a transportable format that represents a high-fidelity representation of the object.
You then may also take the serialized representation, transport it to another context such as a different machine, and rebuild your original object.
When implementing the ISerializable
interface, a class must provide the GetObjectData method that is included in the interface, as well as a specialized constructor that is specialized to accept two parameters: an instance of SerializationInfo, and an instance of StreamingContext.
If your classes don't require fine-grained control of their object state, then you could just use [Serializable]
attribute. Classes that require more control over the serialization process can implement the ISerializable interface.