In This Topic
DOM serialization allows you to save / load the state of any NNode derived object to XML or Binary file or stream.
Saving Node State
The following code snippet shows how to save the state of "someNode" to a stream in binary format:
Saving Node State to a Stream |
Copy Code
|
NDomNodeSerializer serializer = new NDomNodeSerializer();
serializer.SaveToStream(new NNode[] { someNode }, stream, ENPersistencyFormat.Binary);
|
Similarly saving a node state to a file is achieved with the following code:
Saving Node State to a File |
Copy Code
|
NDomNodeSerializer serializer = new NDomNodeSerializer();
serializer.SaveToFile(new NNode[] { someNode }, "c:\\someFile.bin", ENPersistencyFormat.Binary);
|
Loading Node State
In order to load a node which was previously persisted in a stream or file you must use the NDomNodeDeserializer:
Loading Node State From a Stream |
Copy Code
|
NDomNodeDeserializer deserializer = new NDomNodeDeserializer();
NNode someNode = deserializer.LoadFromStream(stream, ENPersistencyFormat.Binary)[0];
|
Loading Node State From a File |
Copy Code
|
NDomNodeDeserializer deserializer = new NDomNodeDeserializer();
NNode someNode = deserializer.LoadFromFile("c:\\someFile.bin", ENPersistencyFormat.Binary)[0];
|
Excluding Node Properties From Serializaton
By default all properties and children declared for a node are serializable. If you wish to exclude a property from serialization you must mark it as non serializable:
Excluding Properties from DOM Serialization |
Copy Code
|
someProperty.SetSerializable(false);
|
Implementing Custom Serializable Objects
When a property type is not an object derived from NNode or a primitive type (double, char, string etc.) you must implement the INDeeplyClonable and INDomCustomSerializable interfaces in order for this property to be registered. The following code snippet shows how to create a simple struct that can be assigned as a property type in a NNode object:
Excluding Properties from DOM Serialization |
Copy Code
|
public struct NMyPoint : INDeeplyCloneable, INDomCustomSerializable
{
public NMyPoint(double x, double y)
{
X = x;
Y = y;
}
// INDeeplyCloneable Members
public object DeepClone()
{
return new NMyPoint(X, Y);
}
// INDomCustomSerializable Members
public void Serialize(NPropertyBag propertyBag)
{
propertyBag.SetDoubleValue("X", X);
propertyBag.SetDoubleValue("Y", Y);
}
public void Deserialize(NPropertyBag propertyBag)
{
X = propertyBag.GetDoubleValue("X");
Y = propertyBag.GetDoubleValue("Y");
}
// Fields
public double X;
public double Y;
}
|
The INDomCustomSerializable interface declares two methods Serialize and Deserialize, which are called during serialization and deserialization respectively. Both have a single property bag argument that provides methods for reading and writing of all primitive types and arrays.
All classes that implement the INDomCustomSerializable interface must also have a public, parameterless constructor.
Implementing Singleon Objects Serialization
There are cases when an object can have only a limited number of instances. In programming this pattern is called singleton. Singleton serialization is slightly different as the serializer must not create instances of a singleton object. Instead when serializing a singleton the serializer replaces that object with another object (called surrogate). Later when deserialization occurs this surrogate is created and asked to provide a reference to the singleton object.
Let's first take a look at the singleton object which we want to make serializable:
Singleton Object |
Copy Code
|
public class NMySingleton : INDeeplyCloneable, INDomSurrogateSerializable
{
private NMySingleton()
{
}
// INDeeplyCloneable
public object DeepClone()
{
return this;
}
// INDomSurrogateSerializable
public INDomSurrogateSerializer DomSurrogateSerializer
{
get
{
return new NMySurrogate(this);
}
}
public static NMySingleton InstanceA = new NMySingleton();
public static NMySingleton InstanceB = new NMySingleton();
}
|
This class can have only two instances (its constructor is marked as private) and those instances are accessible from the InstanceA and InstanceB static fields. In order for it to be compatible with DOM serialization we implement the INDomSurrogateSerializable interface. This interface has only one member - the DomSurrogateSerializer property which returns an instance of an object which is used to serialize the state of the singleton. Following is the implementation of the NMySurrogate class:
Surrogate Serializer Object |
Copy Code
|
public class NMySurrogate : INDomSurrogateSerializer
{
public NMySurrogate()
{
}
public NMySurrogate(NMySingleton instance)
{
IsInstanceA = instance == NMySingleton.InstanceA;
}
public object GetDomRealObject(NDomDeserializationContext context)
{
if (IsInstanceA)
{
return NMySingleton.InstanceA;
}
else
{
return NMySingleton.InstanceB;
}
}
public void Deserialize(NPropertyBag propertyBag)
{
IsInstanceA = propertyBag.GetBooleanValue("IsInstanceA");
}
public void Serialize(NPropertyBag propertyBag)
{
propertyBag.AddValue("IsInstanceA", IsInstanceA);
}
bool IsInstanceA;
}
|
Note that this class implements the INDomSurrogateSerializer interface, which inherits from the INDomCustomSerializable interface. It also has two constructors - one without parameters (which is required in order for the deserializer to create empty instances) and one with parameters which we use in the singleton object implementation.
Now lets take a look at the sequence in which the serializer / deserializer will invoke the methods / properties of those two classes.
Serialization
1. The serializer encounters an object marked as INDomSurrogateSerializable.
2. The serializer calls the DomSurrogateSerializer property and gets a reference to a NMySurrogate object.
3. The serializer calls the Serialize method of the NMySurrogate object.
Deserialization
1. The deserializer creates an instance of a custom object - in this case an instance of the NMySurrogate class using the public, parameterless constructor.
2. The deserializer detects that this object is marked as custom serializable (implements the INDomCustomSerializable interface) and calls the Deserialize method.
3. The deserializer detects that this object is marked as a surrogate serializer (implements the INDomSurrogateSerializer interface) and calls the GetDomRealObject method.
4. The deserializer uses the value returned from GetDomRealObject method.