Сериализировать класс со структурами того же типа

Я пытаюсь сериализовать XML класс, содержащий две структуры с одинаковым именем:

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

В результате ошибка:

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.

Все, что я нашел до сих пор, связано с украшением Type атрибутом XML. Я не могу напрямую украшать любую структуру, так как это не мой код.

Я чувствую, что мне не хватает чего-то простого здесь... Есть ли атрибут XML, который я могу применить к полям?

EDIT Я добавил ответ, используя пару суррогатных свойств. Я не доволен этой конкретной реализацией, поскольку она оставляет общедоступные свойства висящими.

Я также рассматривал вариант DataContractSerialization, но пока не решаюсь сделать следующий шаг. У кого-нибудь еще есть что-то, что они могут предложить?

РЕДАКТИРОВАТЬ 2 Возможно, в моей формулировке была некоторая путаница. Я могу изменить и украсить MyClass, WSize и DSize. Однако, возможно, очевидно, что я не могу изменить System.Windows.Size или System.Drawing.Size.


person MikeH    schedule 20.04.2015    source источник


Ответы (3)


Вы можете сделать это через прокси с настраиваемой XML-сериализацией, я создал этот полностью рабочий пример, хотя для начала нужно выполнить много проверок ошибок.

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


}
person Ron Beyer    schedule 21.04.2015
comment
Фу... Это было бы кошмаром для моего огромного класса. Я отмечу это как ответ, если не смогу получить что-то еще. - person MikeH; 21.04.2015
comment
Возможно, я неправильно понял, если вы можете изменить MyClass, просто поместите туда код сериализации и не используйте прокси, я думал, что вы не можете изменить MyClass, чтобы украсить его... - person Ron Beyer; 21.04.2015
comment
Да, я могу изменить MyClass, я не могу изменить Size структуры. Так что, возможно, ваше решение немного более разумно. - person MikeH; 21.04.2015

Вот возможность, которой я не очень доволен (не очень чисто):

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;
    }
  }
}
person MikeH    schedule 21.04.2015

В итоге я создал новый класс для размещения System.Drawing.Size. В этом новом классе я создал неявные операторы и обработал некоторые конструкторы. Это позволило мне сериализоваться и не менять существующий код:

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

  }
}
person MikeH    schedule 21.04.2015