XML Serialization of an object initialized as array

狂风中的少年 提交于 2019-12-20 04:17:49

问题


My question is probably arising from a basic misunderstanding of XML serialization, but anyways...
I'm trying to serialize a class containing an object which was initialized with an array using XMLSerializer class. Minimal example:

using System;
using System.IO;
using System.Xml.Serialization;

namespace XMLSerializationTest
{
class Program
{
    static void Main(string[] args)
    {           
        try
        {                
            string xmlFileName = Environment.CurrentDirectory + @"\somename.xml";
            XmlSerializer writer = new XmlSerializer(typeof(MyClass));
            FileStream file = File.Create(xmlFileName);
            MyClass someclass = new MyClass();
            writer.Serialize(file, someclass);
            file.Close();
        }
        catch (Exception exc)
        {
            Console.WriteLine(exc);
        }
        Console.ReadLine();
    }        
}
public class MyClass
{
    public object myObject;
    public MyClass()
    {
        myObject = new string[1] { "somestring" };
    }
}
}

However, this throws System.InvalidOperationException, reading the array can't be used here. It works fine, if one replaces the array within the MyClass constructor, e.g., with a simple string like myObject = "somestring";. Unfortunately, I just don't know if my object will be an array or not in advance. So is there any possibility to solve this problem e.g. with attributes or is XML just the wrong way to go in this case?


回答1:


Your difficulty arises from the fact that XmlSerializer requires all types to be serialized to be discoverable statically, through reflection. However, your type MyClass has a polymorphic object property where a instance of a subtype of object -- specifically string [] -- is being stored. When XmlSerializer encounters it, since objects of this type are not expected, the serializer throws the exception you see.

When serializing polymorphic properties such as this, it is necessary to use XML serialization attributes to declare the types that can be encountered. XmlSerializer provides two mechanisms to accomplish this.

  1. Declare the possible polymorphic subtypes using XmlInclude(Type) attributes on the containing type. Since string and string [] are the possible types of your object property, you would do:

    [XmlInclude(typeof(string))]
    [XmlInclude(typeof(string[]))]
    public class MyClass
    {
        public object myObject { get; set; }
    
        public MyClass()
        {
            myObject = new string[] { "somestring" };
        }
    }
    

    And the resulting XML will look like:

    <MyClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <myObject xsi:type="ArrayOfString">
            <string>somestring</string>
        </myObject>
    </MyClass>
    

    Notice the xsi:type attribute? That is a w3c standard attribute that allows the element to assert its type explicitly. Its presence allows XmlSerializer to deserialize the XML into the same type of objects as were originally serialized.

    (Note that [XmlInclude(typeof(string))] seems to be unnecessary as string is apparently a built-in known type - though I cannot find documentation confirming this.)

  2. Declare the possible polymorphic subtypes using [XmlElement(String, Type)] on the polymorphic property itself. Thus you would do something like:

    public class MyClass
    {
        [XmlElement("myObjectString", typeof(string))]
        [XmlElement("myObjectStringArray", typeof(string[]))]
        public object myObject { get; set; }
    
        public MyClass()
        {
            myObject = new string[] { "somestring" };
        }
    }
    

    And the XML generated will look like:

    <MyClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <myObjectStringArray>
            <string>somestring</string>
        </myObjectStringArray>
    </MyClass>
    

    Notice that the name of the myObject element been modified to the string passed to into the [XmlElement(String, Type)] attribute constructor. This allows XmlSerializer to deserialize the XML into the same type of objects as were originally serialized.



来源:https://stackoverflow.com/questions/38212559/xml-serialization-of-an-object-initialized-as-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!