472,782 Members | 1,237 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes and contribute your articles to a community of 472,782 developers and data experts.

How To : Apply XmlSerialization with an Interface

179 100+
This is a little bit more of an advanced topic for serialization. For those who don't know what XML serialization is, then this probably isn't for you just yet. For those that do, you may have come across the problem of serializing an interface, something that you simply can't do using the standard XmlSerialization techniques. This articles looks at how to do that, although it might be a little length. Lets take the following problem:

Expand|Select|Wrap|Line Numbers
  1.  public interface IPoint
  2.     {
  3.         double X;
  4.         double Y;
  5.         double DistanceBetween(IPoint point);
  6.     }
  8.     public class Point2Dimensional : IPoint
  9.     {
  10.         public double X { get; protected set; }
  11.         public double Y { get; protected set; }
  12.         public virtual double DistanceBetween(IPoint point) { ... }
  13.     }
  15.     public class Point3Dimensional : Point2Dimensional
  16.     {
  17.         public double Z { get; protected set; }
  18.         public override double  DistanceBetween(IPoint point) { ... }
  19.     }
If we now have a class that has an IPoint.

Expand|Select|Wrap|Line Numbers
  1.     public class PointHolder
  2.     {
  3.         public IPoint Point { get; set; }
  4.     }
This now means that we cannot deserialize the PointHolder class using standard serialization, because the serializer isn't clever enough to figure out the type it should be deserializing. However, it is possible to do so manually, using some custom serialization.

Firstly we want to make sure both our points can serialize / deserialize themselves. So we change our code slightly. I've ommitted the parameterless constructors, obviously you'll need to add those in.

1) Make the IPoint interface implement IXmlSerializable

Expand|Select|Wrap|Line Numbers
  1.  public interface IPoint : IXmlSerializable
  2.     {
  3.         double X;
  4.         double Y;
  5.         double DistanceBetween(IPoint point);
  6.     }
2) Make the Point2Dimensional and Point3Dimensional implement the IXmlSerializable interface like so. I've just done the 2Dimensional class, obviously the other just adds Z to the list of things to serialize/deserialize.

Expand|Select|Wrap|Line Numbers
  1.    public class Point2Dimensional : IPoint
  2.     {
  3.         public double X { get; protected set; }
  4.         public double Y { get; protected set; }
  5.         public virtual double DistanceBetween(IPoint point) { ... }
  7.         public System.Xml.Schema.XmlSchema GetSchema()
  8.         {
  9.             return null;
  10.         }
  12.         public void ReadXml(System.Xml.XmlReader reader)
  13.         {
  14.             this.X = Convert.ToDouble(reader.GetAttribute("X"));
  15.             this.Y = Convert.ToDouble(reader.GetAttribute("Y"));
  16.         }
  18.         public void WriteXml(System.Xml.XmlWriter writer)
  19.         {
  20.             writer.WriteAttributeString("X", this.X.ToString());
  21.             writer.WriteAttributeString("Y", this.Y.ToString());
  22.         }
  23.     }
We now need to make our PointHolder implement IXmlSerializable too. This uses some extension methods which do the hardwork which we'll see in a minute. Again you'll need your parameterless constructor in there too.

Expand|Select|Wrap|Line Numbers
  1.     public class PointHolder : IXmlSerializable
  2.     {
  3.         public IPoint Point { get; set; }
  5.         public System.Xml.Schema.XmlSchema GetSchema()
  6.         {
  7.             return null;
  8.         }
  10.         public void ReadXml(System.Xml.XmlReader reader)
  11.         {
  12.             this.Point = reader.ReadXmlSerializableElement<IPoint>("Point");
  13.         }
  15.         public void WriteXml(System.Xml.XmlWriter writer)
  16.         {
  17.             writer.SaveXmlSerialiableElement("Point", this.Point);
  18.         }
  19.     }
What we do here, is basically pass in an element name, and either save or assign our Point property. Now lets take a look at the extension methods defined somewhere in a static class.

Expand|Select|Wrap|Line Numbers
  1. public static void SaveXmlSerialiableElement<T>(this XmlWriter writer, String elementName, T element) where T : IXmlSerializable
  2.         {
  3.             writer.WriteStartElement(elementName);
  4.             writer.WriteAttributeString("TYPE", element.GetType().ToString());
  5.             element.WriteXml(writer);
  6.             writer.WriteEndElement();
  7.         }
What's going on here? Well we write a new element with the given name, we then save the full type and namespace of that element, call through to the WriteXml on the element itself, then write the end tag. So the XML will look something like:

<Point3Dimensional TYPE="TestApp.Point3Dimensional" x="0", y="0", z="0">

Not too difficult. Reading is where things get interesting. There's a couple of methods that I won't go into that you'll need, I'm sure you can figure them out. The code is here:

Expand|Select|Wrap|Line Numbers
  1.      public static void ReadToElement(this XmlReader reader, String element)
  2.         {
  3.             reader.ReadToNextNode();
  4.             while (reader.Name != element)
  5.             {
  6.                 reader.ReadToNextNode();
  7.             }
  8.         }
  10.         public static void ReadToNextNode(this XmlReader reader)
  11.         {
  12.             // Read the current item to throw it away
  13.             reader.Read();
  15.             // Keep on reading till we have read all the whitespace
  16.             while (reader.NodeType == XmlNodeType.Whitespace)
  17.             {
  18.                 reader.Read();
  19.             }
  20.         }
The part that is really useful however is:

Expand|Select|Wrap|Line Numbers
  1.   public static T ReadXmlSerializableElement<T>(this XmlReader reader, String elementName) where T : IXmlSerializable
  2.         {
  3.             reader.ReadToElement(elementName);
  5.             Type elementType = Type.GetType(reader.GetAttribute("TYPE"));
  6.             T element = (T)Activator.CreateInstance(elementType);
  7.             element.ReadXml(reader);
  8.             return element;
  9.         }
What this does, is firstly locates the element of interest. Then we read out the type of the element and create a new instance of it. We can then call through to the ReadXml on the element to initalize all it's members and return it.

This then means we can use XmlSerialization on our PointHolder regardless of the type of IPoint that it is storing within the Point property.
Jul 6 '09 #1
0 3868

Sign in to post your reply or Sign up for a free account.

Similar topics

by: Omkar Singh | last post by:
When I serialize my class using XmlSerialization.serialize, it make a lot of reference in the output document. Is there any way to off XmlSerialiation class to make references.
by: Omkar Singh | last post by:
I am using XmlSerialization and XmlDeserialization for making soap Body part. Then I am making sopa-header and other part of soap envelope manually. At last joining all part to get complete soap...
by: Omkar Singh | last post by:
I have a problem while using XmlSerialization. XmlSerializaion creates a lot of 'href' and namespaces while serializing a complex object. Can we control serialization to stop href and namespaces. ...
by: STom | last post by:
I have just started reading up on XMLSerialization and still do not understand the practical use of this technology. For example, if I have to know the class type on the client and on the web...
by: A programmer desperatly needing help! | last post by:
I use the xmlserialization on asp.net pages and on previous machines it never gave a problem. But now i somethings get a: Timed out waiting for a program to execute. The command being executed was...
by: pfrisbie | last post by:
I am developing a Web Services interface with C# and our partner is using Java (Axis 1.1). They require me to include xsi:types in the SOAP Messages I send them. For example: <Partner...
by: LW | last post by:
Hi! I am getting the following error message for my fairly simple web service. I have classes and have two DataSets that reference the same classes. The error is: The XML element named...
by: Frank | last post by:
Hi, Let's say I have a file named myFile.xml Within that file I have blocks of data which I'd like to add at different times during the day. e.g. <LogEntry>
by: =?Utf-8?B?R2FyeQ==?= | last post by:
I have Line, Rect, and Ellipse classes derived from IShape interface, and am using the generic list, List<IShape>, to store a bunch of objects. When I used XMLSerializer object to serialize this...
by: Rina0 | last post by:
Cybersecurity engineering is a specialized field that focuses on the design, development, and implementation of systems, processes, and technologies that protect against cyber threats and...
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 2 August 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM) The start time is equivalent to 19:00 (7PM) in Central...
by: erikbower65 | last post by:
Using CodiumAI's pr-agent is simple and powerful. Follow these steps: 1. Install CodiumAI CLI: Ensure Node.js is installed, then run 'npm install -g codiumai' in the terminal. 2. Connect to...
by: erikbower65 | last post by:
Here's a concise step-by-step guide for manually installing IntelliJ IDEA: 1. Download: Visit the official JetBrains website and download the IntelliJ IDEA Community or Ultimate edition based on...
by: Taofi | last post by:
I try to insert a new record but the error message says the number of query names and destination fields are not the same This are my field names ID, Budgeted, Actual, Status and Differences ...
by: DJRhino1175 | last post by:
When I run this code I get an error, its Run-time error# 424 Object required...This is my first attempt at doing something like this. I test the entire code and it worked until I added this - If...
by: DJRhino | last post by:
Private Sub CboDrawingID_BeforeUpdate(Cancel As Integer) If = 310029923 Or 310030138 Or 310030152 Or 310030346 Or 310030348 Or _ 310030356 Or 310030359 Or 310030362 Or...
by: lllomh | last post by:
Define the method first this.state = { buttonBackgroundColor: 'green', isBlinking: false, // A new status is added to identify whether the button is blinking or not } autoStart=()=>{
by: Mushico | last post by:
How to calculate date of retirement from date of birth

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.