Xml Serialization example needed

Topics: serialization
Sep 29, 2010 at 9:43 AM
Edited Sep 29, 2010 at 10:12 AM

Hi,

First of all thanks a lot for that powerful and well-designed library !

The only problem is that I can't find any documentation about some parts of your work.
In particular, there is nothing about Xml Serialization when using custom fields.

The wiki documentation about this subject (http://quickgraph.codeplex.com/wikipage?title=Xml%20Serialization&referringTitle=Documentation) indicates how it should work, but it's a bit hard to understand all the stuff as the example does not cover "deserializing" part and "custom fields" part.

I can't make the serialization/deserialization process work with custom fields.

Here is what I wrote (sorry for the indentation, the code snippet isn't supported by my Opera browser) :

using (var xwriter = XmlWriter.Create(outputFile1))
      QuickGraph.Serialization.SerializationExtensions.SerializeToXml<MyVertex, MyEdge, AdjacencyGraph<MyVertex, MyEdge>>(theGraph1, 
            xwriter,
            v => v.ID.ToString(),
            e => e.Id.ToString(),
            "graph", "v", "e", "");

where :
- theGraph1 is a AdjacencyGraph<MyVertex, MyEdge> graph
- MyVertex is a simple class with an unique int32 "ID" field
- MyEdge is a custom class with some simple custom fields (int32, string...) and a custom int32 "ID" field that I manage

This does not work. The graph is serialized, but custom fields are not saved (only source, target and ID for the edges).

Here's what I get, for instance : <e id="7456456" source="1456146" target="465496" />

I'm sure I should use

public static void SerializeToXml<TVertex, TEdge, TGraph>(this TGraph graph, XmlWriter writer, VertexIdentity<TVertex> vertexIdentity, EdgeIdentity<TVertex, TEdge> edgeIdentity, string graphElementName, string vertexElementName, string edgeElementName, string namespaceUri, Action<XmlWriter, TGraph> writeGraphAttributes, Action<XmlWriter, TVertex> writeVertexAttributes, Action<XmlWriter, TEdge> writeEdgeAttributes)

but what are the last parameters ???

Could you please provide an example ?

Oh, btw, I think there is a typo in your wiki example ("MyVexte").

Thx !

Sep 29, 2010 at 12:49 PM

Hi,

I finally found the way to write my code, but there still is a problem with the deserialization process...

Here's my code that deserializes :

 

using (var xreader = XmlReader.Create(xmlInputFile))
	res = QuickGraph.Serialization.SerializationExtensions.DeserializeFromXml<MyVertex, MyEdge, AdjacencyGraph<MyVertex, MyEdge>>(
		xreader, 
		"graph", "vertex", "edge", "",
		xr => new AdjacencyGraph<MyVertex, MyEdge>(),
		xr => new MyVertex(Int32.Parse(xr.GetAttribute("id"), CultureInfo.InvariantCulture)),
		xr => new MyEdge(xr.GetAttribute("id"), xr.GetAttribute("source"), xr.GetAttribute("target"), xr.GetAttribute("length")));

It throws a KeyNotFoundException... It's because the deserialization can't find target/source for my edges, because references between vertices are not the same. When an object is used as a key for a list, you can't use another instance of the key even if they ara equal. It's the same problem as here :

class Test
{
	public void go()
	{
		Dictionary<MyKeyObject, String> dico = new Dictionary<MyKeyObject,string>();
		MyKeyObject key1 = new MyKeyObject() { ID = 4 };
		MyKeyObject key2 = new MyKeyObject() { ID = 4 };

		dico.Add(key1, "test");
		Console.WriteLine(dico[key2]);  // Not same references, so it throws KeyNotFoundException
	}
}
   class MyKeyObject
    {
        public int ID;
    }


 
key1 and key2 looks identical but the're not. References must be equal to use an object as a key. It's the same problem for the vertices.


So I've looked at your XmlSerializationTest.cs file, and there's no problem as vertices are simple strings (no reference problem with strings). But how would you deal with a custom class as a vertex ??

Thanks,

Developer
Sep 29, 2010 at 4:13 PM

Override the Equals and GetHashCode methods in your custom class.  The default logic in the object class is to test for equality of reference.  

Since strings are memoized, all equal strings have the same reference.

Sep 29, 2010 at 4:28 PM

I tried to override Equals and the result was the same... but I did not tried with GetHashCode. Thanks for the information, I'll try this !

Sep 30, 2010 at 8:09 AM

 

Hi rhennig,

This worked perfectly, thanks a lot !

The only problem is now a performance issue.

I guess it's my HashCode function (which in fact simply returns the vertex ID to guarantee same return value for same vertices) that is not well distributed.
Or maybe Int32 values are always much faster than Objects as keys for collections ?

Developer
Sep 30, 2010 at 6:51 PM

When debugging performance issues, measuring is always better than guessing what's wrong.  Try running the VS profiler to see where the most time is being spent.

Oct 1, 2010 at 8:20 AM

Well actually it's not just a guess. Performance is way worse when using custom class than a simple Int32 as a key for a collection.
GetHashCode() and Equals() functions are called once per comparison, and it uses approximatively 30 times more CPU when used with a custom class than when used with an Int32.
Calls to GetHashCode() and Equals() then represent 25-30% of the whole process when using a ShortestPathsDijkstra algorithm for instance.
And this does even not take into account the probably bad distribution of my GetHashCode function (which is critical for key-related operations).

So yes, using a custom class with custom fields as a Vertex adds a large CPU overhead compared to Int32.

Anyway, thanks again for your help !