2

I'm trying to XML serialize a class that contains two structs with the same name:

public class MyClass 
{
  public System.Windows.Size WSize = new System.Windows.Size();
  public System.Drawing.Size DSize = new Size.Drawing.Size();
}

The resulting error:

Types 'System.Drawing.Size' and 'System.Windows.Size' both use the XML type name, 
'Size', from namespace ''. Use XML attributes to specify a unique XML name and/or 
namespace for the type.

Everything I've found so far involves decorating the Type with an XML attribute. I can't directly decorate either struct since they are not my code.

I feel like I'm missing something easy here...Is there an XML attribute that I can apply to the fields?

EDIT I've added answer using a couple surrogate properties. I'm not happy with that particular implementation since it leaves public properties hanging out.

I've also considered DataContractSerialization but I'm hesitant to take that next step quite yet. Anyone else have something they can suggest?

EDIT 2 There may have been some confusion in my wording. I can modify and decorate MyClass, WSize and DSize. However, perhaps obviously, I cannot modify System.Windows.Size or System.Drawing.Size.

MikeH
  • 4,242
  • 1
  • 17
  • 32

3 Answers3

2

You can do it by proxy with custom XML serialization, I created this fully working example, although there is a lot of error checking to be done its a place to start.

public class MyClass
{
    public System.Windows.Size WSize = new System.Windows.Size();
    public System.Drawing.Size DSize = new System.Drawing.Size();
}

public class MyClassProxy : MyClass, IXmlSerializable
{
    public new System.Windows.Size WSize { get { return base.WSize; } set { base.WSize = value; } }
    public new System.Drawing.Size DSize { get { return base.DSize; } set { base.DSize = value; } }

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
        reader.MoveToContent();
        reader.ReadStartElement();
        string wheight = reader["height"];
        string wwidth = reader["width"];
        int w, h;
        w = int.Parse(wwidth);
        h = int.Parse(wheight);
        WSize = new Size(w, h);
        reader.ReadStartElement();
        string dheight = reader["height"];
        string dwidth = reader["width"];
        w = int.Parse(dwidth);
        h = int.Parse(dheight);
        DSize = new System.Drawing.Size(w, h);
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        writer.WriteStartElement("MyClassProxy");
        writer.WriteStartElement("WSize");
        writer.WriteAttributeString("height", WSize.Height.ToString());
        writer.WriteAttributeString("width", WSize.Width.ToString());
        writer.WriteEndElement();
        writer.WriteStartElement("DSize");
        writer.WriteAttributeString("height", DSize.Height.ToString());
        writer.WriteAttributeString("width", DSize.Width.ToString());
        writer.WriteEndElement();
        writer.WriteEndElement();
    }
}

class Program
{
    static void Main(string[] args)
    {
        MyClassProxy p = new MyClassProxy();
        p.DSize = new System.Drawing.Size(100, 100);
        p.WSize = new Size(400, 400);

        string xml = "";

        using (StringWriter sw = new StringWriter())
        {
            System.Xml.XmlWriter wr = System.Xml.XmlWriter.Create(sw);
            p.WriteXml(wr);
            wr.Close();
            xml = sw.ToString();
        }

        MyClassProxy p2 = new MyClassProxy();

        using (StringReader sr = new StringReader(xml))
        {
            System.Xml.XmlReader r = System.Xml.XmlReader.Create(sr);
            p2.ReadXml(r);
        }

        MyClass baseClass = (MyClass)p2;

        Print(baseClass);

        Console.ReadKey();
    }

    static void Print(MyClass c)
    {
        Console.WriteLine(c.DSize.ToString());
        Console.WriteLine(c.WSize.ToString());
    }


}
Ron Beyer
  • 11,003
  • 1
  • 19
  • 37
  • 1
    Yuck...This would be a nightmare to implement on my huge class. I'll mark this as the answer if I can't get anything else. – MikeH Apr 21 '15 at 16:03
  • I may have misunderstood, if you can modify MyClass then just put the serialization code there and don't use the proxy, I thought you couldn't modify MyClass to decorate it... – Ron Beyer Apr 21 '15 at 16:25
  • Yes, I can modify `MyClass`, I cannot modify the `Size` structs. So perhaps your solution is a bit more tenable. – MikeH Apr 21 '15 at 16:42
0

Here's a possibility that I'm not terribly happy with (not very clean):

public class MyClass 
{
  public System.Windows.Size WSize = new System.Windows.Size();

  [XmlIgnore]
  public System.Drawing.Size DSize = new Size();

  public int DSizeWidthForSerialization
  {
    get
    {
      return DSize.Width;
    }
    set
    {
      DSize.Width = value;
    }
  }
  public int DSizeHeightForSerialization
  {
    get
    {
      return DSize.Height;
    }
    set
    {
      DSize.Height = value;
    }
  }
}
MikeH
  • 4,242
  • 1
  • 17
  • 32
0

I ended up creating a new class to house System.Drawing.Size. Within that new class I created implicit operators and handled some of the constructors. This allowed me to serialize and not have to change any existing code:

public class MyClass 
{
  public System.Windows.Size WSize = new System.Windows.Size();
  public MyDrawingSize DSize = new System.Drawing.Size();

  public class MyDrawingSize
  {
    public int Height, Width;

    public MyDrawingSize() { } //Needed for deserialization
    public MyDrawingSize(int width, int height)
    {
      Width = width;
      Height = height;
    }
    public static implicit operator System.Drawing.Size(MyDrawingSize size)
    {
      return new System.Drawing.Size(size.Width, size.Height);
    }
    public static implicit operator MyDrawingSize(System.Drawing.Size size)
    {
      return new MyDrawingSize() { Width = size.Width, Height = size.Height };
    }

  }
}
MikeH
  • 4,242
  • 1
  • 17
  • 32