Custom Serialization
-
Hi there ! I have a tricky little problem. First I have to elaborate on my custom application architecture. I am desigining a highly extensible game engine which gets almost all functionality out of plugins which are implemented as .NET assemblies. I have a class called "Node" which wraps dynamically loaded classes via their object base class and supports invocation of methods via reflection as well as other things.. Nodes are organized in a hierarchy . Every Node contains a SortedList storing all child nodes, as well as a Node Reference pointing to the Parent node of a given node, as well as an object reference pointing to the wrapped class ( which was imported from the plugin assembly ) Now i want to save the hierarchy to a file via serialization. However i only want to save parts of the hierarchy from a given node. However since there is a parent reference , always the whole hierarchy gets serialized since the serializer walks both ways automatcially. So i want to restrict the serialization of the parent reference in certain cases dynamically. I can'T just add "Noserialze" attribute to the parent reference, since all classes are wrapped in Nodes and there can't be derived classes. Because of that i want to support ISerialize on the Node class to control what gets serialized and stop at a given node. However i do not seem to get that working. In particular how do i have to serialize the SortedList for the child nodes ? This is what i have so far: public void Node.GetObjectData( SerializationInfo info,StreamingContext context ) { info.AddValue("Id",m_identifier ); // Store the node id foreach( Node n in m_children.Values ) { string name = n.Name; info.AddValue ( "Name",name ); info.AddValue ( "Node",n ); } if ( m_parentSerialize ) info.AddValue("Parent",n.Parent ); } However this does not seem to work I also tried calling GetObjectData for the child nodes.. Seems not to work either.. . Any clues ?
-
Hi there ! I have a tricky little problem. First I have to elaborate on my custom application architecture. I am desigining a highly extensible game engine which gets almost all functionality out of plugins which are implemented as .NET assemblies. I have a class called "Node" which wraps dynamically loaded classes via their object base class and supports invocation of methods via reflection as well as other things.. Nodes are organized in a hierarchy . Every Node contains a SortedList storing all child nodes, as well as a Node Reference pointing to the Parent node of a given node, as well as an object reference pointing to the wrapped class ( which was imported from the plugin assembly ) Now i want to save the hierarchy to a file via serialization. However i only want to save parts of the hierarchy from a given node. However since there is a parent reference , always the whole hierarchy gets serialized since the serializer walks both ways automatcially. So i want to restrict the serialization of the parent reference in certain cases dynamically. I can'T just add "Noserialze" attribute to the parent reference, since all classes are wrapped in Nodes and there can't be derived classes. Because of that i want to support ISerialize on the Node class to control what gets serialized and stop at a given node. However i do not seem to get that working. In particular how do i have to serialize the SortedList for the child nodes ? This is what i have so far: public void Node.GetObjectData( SerializationInfo info,StreamingContext context ) { info.AddValue("Id",m_identifier ); // Store the node id foreach( Node n in m_children.Values ) { string name = n.Name; info.AddValue ( "Name",name ); info.AddValue ( "Node",n ); } if ( m_parentSerialize ) info.AddValue("Parent",n.Parent ); } However this does not seem to work I also tried calling GetObjectData for the child nodes.. Seems not to work either.. . Any clues ?
The way the default serializer works, is it will not serialize an object if it is already serialized, but it will store a value so that when deserialized it will point to the proper object. So you shouldn't have to implement
ISerializable
. Anyway, in your code the problem is the foreach loop. You are adding the node names and the nodes, but they have the same name each time; so you are adding the data but when you go to deserialize it, you are getting the same data back each time. James Simplicity Rules! -
The way the default serializer works, is it will not serialize an object if it is already serialized, but it will store a value so that when deserialized it will point to the proper object. So you shouldn't have to implement
ISerializable
. Anyway, in your code the problem is the foreach loop. You are adding the node names and the nodes, but they have the same name each time; so you are adding the data but when you go to deserialize it, you are getting the same data back each time. James Simplicity Rules!Hi ! THanks for you answer. I know that the serializer stores each object only once. But thats not the idea behind my question, because in my graph there are CERTAIN objects that MUST NOT be serialized... This is because e.g high level objects are in the graph like the graphics renderer or sound engine, which can be different on other machines, but still the serialized files should be loadable. So i need the Iserializeable interface. The code i sent in was just some dummy code, here is the REAL CODE now: private Node ( SerializationInfo info, StreamingContext c ) { m_children = new SortedList(); Debug.WriteLine("Deserializing object"); // And finally the node data itself. m_reference = info.GetValue("WrappedObject",typeof(object) ); m_id = (Identifier)info.GetValue("Id",typeof(Identifier) ); Debug.WriteLine(m_id.Name,"Assigned key to"); // Add number of children int numChildren = (int)info.GetValue( "ChildrenCount",typeof(int) ); // Serialize the child nodes first for( int i = 0; i < numChildren; i++ ) { // Generate an index key string nodeName = "Node" + i; Node newNode = (Node)info.GetValue(nodeName,typeof(Node) ); Attach( newNode ); } // Now we store the parent reference. if ( m_parentSerialize ) m_parent = (Node)info.GetValue("NodeParent",typeof(Node) ); } /// /// Serialization method for nodes. This is required /// so that the class tree does not get walked in the /// wrong direction, since we want certain node wrapped /// classes to be kept out of serialization. /// /// Serialization info. /// Serialization context. public void GetObjectData( SerializationInfo info, StreamingContext context ) { Debug.WriteLine(Id.Name,"GetObjectData called for"); // And finally the node data itself. info.AddValue("WrappedObject",m_reference ); info.AddValue("Id",m_id,typeof(Identifier) ); // Add number of children info.AddValue( "ChildrenCount",m_children.Count ); int index = 0; // Serialize the child nodes first foreach( Node n in m_children.Values ) { // Generate an index ke string nodeIndex = "Node" + index; info.AddValue( nodeIndex,n,typeof(Node) ); index ++; } // Now we store the parent reference. if ( m_parentSerialize ) info.AddValue("NodeParent",m_parent,typeof(Node) ); } The problem now is that
-
Hi ! THanks for you answer. I know that the serializer stores each object only once. But thats not the idea behind my question, because in my graph there are CERTAIN objects that MUST NOT be serialized... This is because e.g high level objects are in the graph like the graphics renderer or sound engine, which can be different on other machines, but still the serialized files should be loadable. So i need the Iserializeable interface. The code i sent in was just some dummy code, here is the REAL CODE now: private Node ( SerializationInfo info, StreamingContext c ) { m_children = new SortedList(); Debug.WriteLine("Deserializing object"); // And finally the node data itself. m_reference = info.GetValue("WrappedObject",typeof(object) ); m_id = (Identifier)info.GetValue("Id",typeof(Identifier) ); Debug.WriteLine(m_id.Name,"Assigned key to"); // Add number of children int numChildren = (int)info.GetValue( "ChildrenCount",typeof(int) ); // Serialize the child nodes first for( int i = 0; i < numChildren; i++ ) { // Generate an index key string nodeName = "Node" + i; Node newNode = (Node)info.GetValue(nodeName,typeof(Node) ); Attach( newNode ); } // Now we store the parent reference. if ( m_parentSerialize ) m_parent = (Node)info.GetValue("NodeParent",typeof(Node) ); } /// /// Serialization method for nodes. This is required /// so that the class tree does not get walked in the /// wrong direction, since we want certain node wrapped /// classes to be kept out of serialization. /// /// Serialization info. /// Serialization context. public void GetObjectData( SerializationInfo info, StreamingContext context ) { Debug.WriteLine(Id.Name,"GetObjectData called for"); // And finally the node data itself. info.AddValue("WrappedObject",m_reference ); info.AddValue("Id",m_id,typeof(Identifier) ); // Add number of children info.AddValue( "ChildrenCount",m_children.Count ); int index = 0; // Serialize the child nodes first foreach( Node n in m_children.Values ) { // Generate an index ke string nodeIndex = "Node" + index; info.AddValue( nodeIndex,n,typeof(Node) ); index ++; } // Now we store the parent reference. if ( m_parentSerialize ) info.AddValue("NodeParent",m_parent,typeof(Node) ); } The problem now is that
What is the code for Attach, from what I can tell everything looks fine there; and how does m_id and newNode interact? I don't see anything that brings them together. James Simplicity Rules!
-
Hi ! THanks for you answer. I know that the serializer stores each object only once. But thats not the idea behind my question, because in my graph there are CERTAIN objects that MUST NOT be serialized... This is because e.g high level objects are in the graph like the graphics renderer or sound engine, which can be different on other machines, but still the serialized files should be loadable. So i need the Iserializeable interface. The code i sent in was just some dummy code, here is the REAL CODE now: private Node ( SerializationInfo info, StreamingContext c ) { m_children = new SortedList(); Debug.WriteLine("Deserializing object"); // And finally the node data itself. m_reference = info.GetValue("WrappedObject",typeof(object) ); m_id = (Identifier)info.GetValue("Id",typeof(Identifier) ); Debug.WriteLine(m_id.Name,"Assigned key to"); // Add number of children int numChildren = (int)info.GetValue( "ChildrenCount",typeof(int) ); // Serialize the child nodes first for( int i = 0; i < numChildren; i++ ) { // Generate an index key string nodeName = "Node" + i; Node newNode = (Node)info.GetValue(nodeName,typeof(Node) ); Attach( newNode ); } // Now we store the parent reference. if ( m_parentSerialize ) m_parent = (Node)info.GetValue("NodeParent",typeof(Node) ); } /// /// Serialization method for nodes. This is required /// so that the class tree does not get walked in the /// wrong direction, since we want certain node wrapped /// classes to be kept out of serialization. /// /// Serialization info. /// Serialization context. public void GetObjectData( SerializationInfo info, StreamingContext context ) { Debug.WriteLine(Id.Name,"GetObjectData called for"); // And finally the node data itself. info.AddValue("WrappedObject",m_reference ); info.AddValue("Id",m_id,typeof(Identifier) ); // Add number of children info.AddValue( "ChildrenCount",m_children.Count ); int index = 0; // Serialize the child nodes first foreach( Node n in m_children.Values ) { // Generate an index ke string nodeIndex = "Node" + index; info.AddValue( nodeIndex,n,typeof(Node) ); index ++; } // Now we store the parent reference. if ( m_parentSerialize ) info.AddValue("NodeParent",m_parent,typeof(Node) ); } The problem now is that
I could be off the mark here but couldn't you just let serialization happen naturally and mark the fields in the graph that you don't want serialized with [NonSerialized()]? Regards