XML 初始化为数组的对象的序列化

XML Serialization of an object initialized as array

我的问题可能是由于对 XML 序列化的基本误解引起的,但无论如何...
我正在尝试序列化一个 class,其中包含一个使用 XMLSerializer class 用数组初始化的对象。最小示例:

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

但是这样会抛出System.InvalidOperationException,这里不能使用读数组。如果用 myObject = "somestring"; 这样的简单字符串替换 MyClass 构造函数中的数组,它工作正常。不幸的是,我只是不知道我的对象是否会预先是一个数组。那么有没有可能解决这个问题,例如有属性还是 XML 在这种情况下只是错误的方法?

你的困难来自这样一个事实,即 XmlSerializer 要求所有类型都被序列化,以便通过反射静态地被发现。但是,您的类型 MyClass 具有多态性 object 属性,其中存储了 object 的子类型的实例——特别是 string []。当 XmlSerializer 遇到它时,由于不需要这种类型的对象,因此序列化程序会抛出您看到的异常。

在序列化诸如此类的多态属性时,需要使用XML serialization attributes来声明可能遇到的类型。 XmlSerializer 提供了两种机制来实现这一点。

  1. 使用包含类型的 XmlInclude(Type) 属性声明可能的多态子类型。因为 stringstring [] 是你的 object 属性 的可能类型,你会做:

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

    结果 XML 看起来像:

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

    请注意 xsi:type attribute? That is a w3c standard attribute 允许元素显式断言其类型。它的存在允许 XmlSerializer 将 XML 反序列化为与最初序列化相同类型的对象。

    (请注意,[XmlInclude(typeof(string))] 似乎是不必要的,因为 string 显然是一个内置的已知类型——尽管我找不到证实这一点的文档。)

  2. 在多态 属性 本身上使用 [XmlElement(String, Type)] 声明可能的多态子类型。因此你会做这样的事情:

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

    生成的 XML 看起来像:

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

    请注意,myObject 元素的名称已修改为传递给 [XmlElement(String, Type)] 属性构造函数的字符串。这允许 XmlSerializer 将 XML 反序列化为与最初序列化相同类型的对象。