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

本文关键字:对象 序列化 数组 初始化 | 更新日期: 2023-09-27 17:54:59

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

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,读取数组不能在这里使用。它工作得很好,如果一个人替换MyClass构造函数中的数组,例如,用一个简单的字符串像myObject = "somestring";。不幸的是,我只是不知道我的对象是否会是一个数组。那么,是否有可能解决这个问题,例如使用属性,或者XML只是在这种情况下的错误方法?

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

您的困难来自XmlSerializer要求所有类型都被序列化,以便通过反射静态地发现。然而,您的类型MyClass具有多态object属性,其中object的子类型的实例-特别是string [] -正在存储。当XmlSerializer遇到此异常时,由于不需要此类型的对象,因此序列化器将抛出您所看到的异常。

在序列化诸如此类的多态属性时,有必要使用XML序列化属性来声明可能遇到的类型。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属性吗?这是一个w3c标准属性,允许元素显式断言其类型。它的存在允许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反序列化为与最初序列化的对象类型相同的对象。