MikeH
MikeH

Reputation: 4395

Serialize class with structs of same type name

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.

Upvotes: 2

Views: 147

Answers (3)

MikeH
MikeH

Reputation: 4395

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 };
    }

  }
}

Upvotes: 0

MikeH
MikeH

Reputation: 4395

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;
    }
  }
}

Upvotes: 0

Ron Beyer
Ron Beyer

Reputation: 11273

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());
    }


}

Upvotes: 2

Related Questions