如何对对象列表数组进行XML序列化?

3

我正在试图将一个C#对象数组的列表保存在一个XML文件中。我成功地保存了一个对象数组和一个对象列表,但是没有保存一个对象列表的数组。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace expirement
{
    public class Box
    {
        public int x;
        public Box(int a)
        {
            x = a;
        }
        public Box()
        {
        }
    }

    public class Program
    {
        static void Main(string[] args)
        {
            List<Box>[] MainArr = new List<Box>[1];
            MainArr[0] = new List<Box>();
            Box Box1 = new Box(1);
            MainArr[0].Add(Box1);
            System.Xml.Serialization.XmlSerializer writer = new System.Xml.Serialization.XmlSerializer(MainArr.GetType());
            System.IO.StreamWriter fileWrite = new System.IO.StreamWriter(@"C:\Users\student\Desktop\ArrListBox.xml");
            writer.Serialize(fileWrite,MainArr);
            fileWrite.Close();
        }
    }
}

i get the error:

Unable to generate a temporary class (result=1).
error CS1026: ) expected
error CS1002: ; expected 
error CS1525: Invalid expression term ')'
error CS1002: ; expected
error CS1525: Invalid expression term ')'

1
我明白你的意思 - 当我尝试创建new XmlSerializer(MainArr.GetType())时,我在Microsoft的代码中得到了NullReferenceException异常。然而,似乎我可以很好地序列化一个List<List<Box>> - AJ Richardson
有没有办法在不将它改为List<List<Box>>的情况下解决这个问题? - Erezwartski
相关链接:http://stackoverflow.com/questions/14836017/xmlserializer-giving-a-null-exception-in-c-sharp - BartoszKP
@BartoszKP:在生成和编译XmlSerializer类时会发生这种情况。 - Patrick Hofman
这看起来像是一个 bug。这段代码在 Ideone 上运行正常。 - BartoszKP
显示剩余7条评论
3个回答

1

我重现了你的错误消息,并发现这确实是来自Microsoft的XML序列化器中的一个错误。

当使用XmlSerializer(type)构造函数时,.NET会自动生成一个名为AssemblyName.XmlSerializer.dll的程序集。该程序集包含实际的类,用于执行您代码的序列化和反序列化。

在空控制台应用程序中运行此代码时,我首先遇到了NullReferenceException,就像其他一些评论中的情况一样。当我尝试使用从List<List<Box>>派生的类进行自动生成程序集时,我获得了合理的代码(您只能预编译类,因此不能为List<Box>[]预编译序列化器)。

最终,当我使用可能是项目中的一个测试类之一的这个类时,我得到了你的错误消息:

public class X
{
    public List<Box>[] Boxes { get; set; }
}

使用 sgen:
"C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\sgen" /t:"expirement.X" /a:ConsoleApplication8.exe /force

这给我带来了与您相同的错误。不幸的是,没有快速解决方案。使用另一种类型似乎可以解决问题。在Microsoft Connect上报告此问题。
作为参考,这是序列化的完整代码(使用sgen中的开关/k)。代码看起来有些混乱,我无法快速修复它:
#if _DYNAMIC_XMLSERIALIZER_COMPILATION
[assembly:System.Security.AllowPartiallyTrustedCallers()]
[assembly:System.Security.SecurityTransparent()]
[assembly:System.Security.SecurityRules(System.Security.SecurityRuleSet.Level1)]
#endif
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
[assembly: System.Xml.Serialization.XmlSerializerVersionAttribute(ParentAssemblyId = @"c80da358-347f-48cf-88a7-0fda1a15c25b,", Version = @"4.0.0.0")]
namespace Microsoft.Xml.Serialization.GeneratedAssembly
{

    public class XmlSerializationWriterX : System.Xml.Serialization.XmlSerializationWriter
    {

        public void Write4_X(object o)
        {
            WriteStartDocument();
            if (o == null)
            {
                WriteNullTagLiteral(@"X", @"");
                return;
            }
            TopLevelElement();
            Write3_X(@"X", @"", ((global::expirement.X)o), true, false);
        }

        void Write3_X(string n, string ns, global::expirement.X o, bool isNullable, bool needType)
        {
            if ((object)o == null)
            {
                if (isNullable) WriteNullTagLiteral(n, ns);
                return;
            }
            if (!needType)
            {
                System.Type t = o.GetType();
                if (t == typeof(global::expirement.X))
                {
                }
                else
                {
                    throw CreateUnknownTypeException(o);
                }
            }
            WriteStartElement(n, ns, o, false, null);
            if (needType) WriteXsiType(@"X", @"");
            {
                global::System.Collections.Generic.List<global::expirement.Box>[] a = (global::System.Collections.Generic.List<global::expirement.Box>[])((global::System.Collections.Generic.List<global::expirement.Box>[])o.@Boxes);
                if (a != null)
                {
                    WriteStartElement(@"Boxes", @"", null, false);
                    for (int ia = 0; ia < a.Length; ia++)
                    {
                        {
                            global::System.Collections.Generic.List<global::expirement.Box> aa = (global::System.Collections.Generic.List<global::expirement.Box>)((global::System.Collections.Generic.List<global::expirement.Box>)a[ia]);
                            if ((object)(aa) == null)
                            {
                                WriteNullTagLiteral(@"ArrayOfBox", @"");
                            }
                            else
                            {
                                WriteStartElement(@"ArrayOfBox", @"", null, false);
                                for (int iaa = 0; iaa < ((System.Collections.ICollection)aa).Count; iaa++)
                                {
                                    Write2_Box(@"Box", @"", ((global::expirement.Box)aa[iaa]), true, false);
                                }
                                WriteEndElement();
                            }
                        }
                    }
                    WriteEndElement();
                }
            }
            WriteEndElement(o);
        }

        void Write2_Box(string n, string ns, global::expirement.Box o, bool isNullable, bool needType)
        {
            if ((object)o == null)
            {
                if (isNullable) WriteNullTagLiteral(n, ns);
                return;
            }
            if (!needType)
            {
                System.Type t = o.GetType();
                if (t == typeof(global::expirement.Box))
                {
                }
                else
                {
                    throw CreateUnknownTypeException(o);
                }
            }
            WriteStartElement(n, ns, o, false, null);
            if (needType) WriteXsiType(@"Box", @"");
            WriteElementStringRaw(@"x", @"", System.Xml.XmlConvert.ToString((global::System.Int32)((global::System.Int32)o.@x)));
            WriteEndElement(o);
        }

        protected override void InitCallbacks()
        {
        }
    }

    public class XmlSerializationReaderX : System.Xml.Serialization.XmlSerializationReader
    {

        public object Read4_X()
        {
            object o = null;
            Reader.MoveToContent();
            if (Reader.NodeType == System.Xml.XmlNodeType.Element)
            {
                if (((object)Reader.LocalName == (object)id1_X && (object)Reader.NamespaceURI == (object)id2_Item))
                {
                    o = Read3_X(true, true);
                }
                else
                {
                    throw CreateUnknownNodeException();
                }
            }
            else
            {
                UnknownNode(null, @":X");
            }
            return (object)o;
        }

        global::expirement.X Read3_X(bool isNullable, bool checkType) {
            System.Xml.XmlQualifiedName xsiType = checkType ? GetXsiType() : null;
            bool isNull = false;
            if (isNullable) isNull = ReadNull();
            if (checkType) {
            if (xsiType == null || ((object) ((System.Xml.XmlQualifiedName)xsiType).Name == (object)id1_X && (object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_Item)) {
            }
            else
                throw CreateUnknownTypeException((System.Xml.XmlQualifiedName)xsiType);
            }
            if (isNull) return null;
            global::expirement.X o;
            o = new global::expirement.X();
            global::System.Collections.Generic.List<global::expirement.Box>[] a_0 = null;
            int ca_0 = 0;
            bool[] paramsRead = new bool[1];
            while (Reader.MoveToNextAttribute()) {
                if (!IsXmlnsAttribute(Reader.Name)) {
                    UnknownNode((object)o);
                }
            }
            Reader.MoveToElement();
            if (Reader.IsEmptyElement) {
                Reader.Skip();
                return o;
            }
            Reader.ReadStartElement();
            Reader.MoveToContent();
            int whileIterations0 = 0;
            int readerCount0 = ReaderCount;
            while (Reader.NodeType != System.Xml.XmlNodeType.EndElement && Reader.NodeType != System.Xml.XmlNodeType.None) {
                if (Reader.NodeType == System.Xml.XmlNodeType.Element) {
                    if (((object) Reader.LocalName == (object)id3_Boxes && (object) Reader.NamespaceURI == (object)id2_Item)) {
                        if (!ReadNull()) {
                            global::System.Collections.Generic.List<global::expirement.Box>[] a_0_0 = null;
                            int ca_0_0 = 0;
                            if ((Reader.IsEmptyElement)) {
                                Reader.Skip();
                            }
                            else {
                                Reader.ReadStartElement();
                                Reader.MoveToContent();
                                int whileIterations1 = 0;
                                int readerCount1 = ReaderCount;
                                while (Reader.NodeType != System.Xml.XmlNodeType.EndElement && Reader.NodeType != System.Xml.XmlNodeType.None) {
                                    if (Reader.NodeType == System.Xml.XmlNodeType.Element) {
                                        if (((object) Reader.LocalName == (object)id4_ArrayOfBox && (object) Reader.NamespaceURI == (object)id2_Item)) {
                                            if (!ReadNull()) {
                                                if ((object)(a_0_0 = (global::System.Collections.Generic.List<global::expirement.Box>[])EnsureArrayIndex(a_0_0, ca_0_0, typeof(global::System.Collections.Generic.List<global::expirement.Box>));a_0_0[ca_0_0++]) == null) a_0_0 = (global::System.Collections.Generic.List<global::expirement.Box>[])EnsureArrayIndex(a_0_0, ca_0_0, typeof(global::System.Collections.Generic.List<global::expirement.Box>));a_0_0[ca_0_0++] = new global::System.Collections.Generic.List<global::expirement.Box>();
                                                global::System.Collections.Generic.List<global::expirement.Box> a_0_0_0 = (global::System.Collections.Generic.List<global::expirement.Box>)a_0_0 = (global::System.Collections.Generic.List<global::expirement.Box>[])EnsureArrayIndex(a_0_0, ca_0_0, typeof(global::System.Collections.Generic.List<global::expirement.Box>));a_0_0[ca_0_0++];
                                                if ((Reader.IsEmptyElement)) {
                                                    Reader.Skip();
                                                }
                                                else {
                                                    Reader.ReadStartElement();
                                                    Reader.MoveToContent();
                                                    int whileIterations2 = 0;
                                                    int readerCount2 = ReaderCount;
                                                    while (Reader.NodeType != System.Xml.XmlNodeType.EndElement && Reader.NodeType != System.Xml.XmlNodeType.None) {
                                                        if (Reader.NodeType == System.Xml.XmlNodeType.Element) {
                                                            if (((object) Reader.LocalName == (object)id5_Box && (object) Reader.NamespaceURI == (object)id2_Item)) {
                                                                if ((object)(a_0_0_0) == null) Reader.Skip(); else a_0_0_0.Add(Read2_Box(true, true));
                                                            }
                                                            else {
                                                                UnknownNode(null, @":Box");
                                                            }
                                                        }
                                                        else {
                                                            UnknownNode(null, @":Box");
                                                        }
                                                        Reader.MoveToContent();
                                                        CheckReaderCount(ref whileIterations2, ref readerCount2);
                                                    }
                                                ReadEndElement();
                                                }
                                            }
                                            else {
                                                if ((object)(a_0_0 = (global::System.Collections.Generic.List<global::expirement.Box>[])EnsureArrayIndex(a_0_0, ca_0_0, typeof(global::System.Collections.Generic.List<global::expirement.Box>));a_0_0[ca_0_0++]) == null) a_0_0 = (global::System.Collections.Generic.List<global::expirement.Box>[])EnsureArrayIndex(a_0_0, ca_0_0, typeof(global::System.Collections.Generic.List<global::expirement.Box>));a_0_0[ca_0_0++] = new global::System.Collections.Generic.List<global::expirement.Box>();
                                                global::System.Collections.Generic.List<global::expirement.Box> a_0_0_0 = (global::System.Collections.Generic.List<global::expirement.Box>)a_0_0 = (global::System.Collections.Generic.List<global::expirement.Box>[])EnsureArrayIndex(a_0_0, ca_0_0, typeof(global::System.Collections.Generic.List<global::expirement.Box>));a_0_0[ca_0_0++];
                                            }
                                        }
                                        else {
                                            UnknownNode(null, @":ArrayOfBox");
                                        }
                                    }
                                    else {
                                        UnknownNode(null, @":ArrayOfBox");
                                    }
                                    Reader.MoveToContent();
                                    CheckReaderCount(ref whileIterations1, ref readerCount1);
                                }
                            ReadEndElement();
                            }
                            o.@Boxes = (global::System.Collections.Generic.List<global::expirement.Box>[])ShrinkArray(a_0_0, ca_0_0, typeof(global::System.Collections.Generic.List<global::expirement.Box>), false);
                        }
                    }
                    else {
                        UnknownNode((object)o, @":Boxes");
                    }
                }
                else {
                    UnknownNode((object)o, @":Boxes");
                }
                Reader.MoveToContent();
                CheckReaderCount(ref whileIterations0, ref readerCount0);
            }
            ReadEndElement();
            return o;
        }

        global::expirement.Box Read2_Box(bool isNullable, bool checkType)
        {
            System.Xml.XmlQualifiedName xsiType = checkType ? GetXsiType() : null;
            bool isNull = false;
            if (isNullable) isNull = ReadNull();
            if (checkType)
            {
                if (xsiType == null || ((object)((System.Xml.XmlQualifiedName)xsiType).Name == (object)id5_Box && (object)((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_Item))
                {
                }
                else
                    throw CreateUnknownTypeException((System.Xml.XmlQualifiedName)xsiType);
            }
            if (isNull) return null;
            global::expirement.Box o;
            o = new global::expirement.Box();
            bool[] paramsRead = new bool[1];
            while (Reader.MoveToNextAttribute())
            {
                if (!IsXmlnsAttribute(Reader.Name))
                {
                    UnknownNode((object)o);
                }
            }
            Reader.MoveToElement();
            if (Reader.IsEmptyElement)
            {
                Reader.Skip();
                return o;
            }
            Reader.ReadStartElement();
            Reader.MoveToContent();
            int whileIterations3 = 0;
            int readerCount3 = ReaderCount;
            while (Reader.NodeType != System.Xml.XmlNodeType.EndElement && Reader.NodeType != System.Xml.XmlNodeType.None)
            {
                if (Reader.NodeType == System.Xml.XmlNodeType.Element)
                {
                    if (!paramsRead[0] && ((object)Reader.LocalName == (object)id6_x && (object)Reader.NamespaceURI == (object)id2_Item))
                    {
                        {
                            o.@x = System.Xml.XmlConvert.ToInt32(Reader.ReadElementString());
                        }
                        paramsRead[0] = true;
                    }
                    else
                    {
                        UnknownNode((object)o, @":x");
                    }
                }
                else
                {
                    UnknownNode((object)o, @":x");
                }
                Reader.MoveToContent();
                CheckReaderCount(ref whileIterations3, ref readerCount3);
            }
            ReadEndElement();
            return o;
        }

        protected override void InitCallbacks()
        {
        }

        string id5_Box;
        string id3_Boxes;
        string id1_X;
        string id2_Item;
        string id6_x;
        string id4_ArrayOfBox;

        protected override void InitIDs()
        {
            id5_Box = Reader.NameTable.Add(@"Box");
            id3_Boxes = Reader.NameTable.Add(@"Boxes");
            id1_X = Reader.NameTable.Add(@"X");
            id2_Item = Reader.NameTable.Add(@"");
            id6_x = Reader.NameTable.Add(@"x");
            id4_ArrayOfBox = Reader.NameTable.Add(@"ArrayOfBox");
        }
    }

    public abstract class XmlSerializer1 : System.Xml.Serialization.XmlSerializer
    {
        protected override System.Xml.Serialization.XmlSerializationReader CreateReader()
        {
            return new XmlSerializationReaderX();
        }
        protected override System.Xml.Serialization.XmlSerializationWriter CreateWriter()
        {
            return new XmlSerializationWriterX();
        }
    }

    public sealed class XSerializer : XmlSerializer1
    {

        public override System.Boolean CanDeserialize(System.Xml.XmlReader xmlReader)
        {
            return xmlReader.IsStartElement(@"X", @"");
        }

        protected override void Serialize(object objectToSerialize, System.Xml.Serialization.XmlSerializationWriter writer)
        {
            ((XmlSerializationWriterX)writer).Write4_X(objectToSerialize);
        }

        protected override object Deserialize(System.Xml.Serialization.XmlSerializationReader reader)
        {
            return ((XmlSerializationReaderX)reader).Read4_X();
        }
    }

    public class XmlSerializerContract : global::System.Xml.Serialization.XmlSerializerImplementation
    {
        public override global::System.Xml.Serialization.XmlSerializationReader Reader { get { return new XmlSerializationReaderX(); } }
        public override global::System.Xml.Serialization.XmlSerializationWriter Writer { get { return new XmlSerializationWriterX(); } }
        System.Collections.Hashtable readMethods = null;
        public override System.Collections.Hashtable ReadMethods
        {
            get
            {
                if (readMethods == null)
                {
                    System.Collections.Hashtable _tmp = new System.Collections.Hashtable();
                    _tmp[@"expirement.X::"] = @"Read4_X";
                    if (readMethods == null) readMethods = _tmp;
                }
                return readMethods;
            }
        }
        System.Collections.Hashtable writeMethods = null;
        public override System.Collections.Hashtable WriteMethods
        {
            get
            {
                if (writeMethods == null)
                {
                    System.Collections.Hashtable _tmp = new System.Collections.Hashtable();
                    _tmp[@"expirement.X::"] = @"Write4_X";
                    if (writeMethods == null) writeMethods = _tmp;
                }
                return writeMethods;
            }
        }
        System.Collections.Hashtable typedSerializers = null;
        public override System.Collections.Hashtable TypedSerializers
        {
            get
            {
                if (typedSerializers == null)
                {
                    System.Collections.Hashtable _tmp = new System.Collections.Hashtable();
                    _tmp.Add(@"expirement.X::", new XSerializer());
                    if (typedSerializers == null) typedSerializers = _tmp;
                }
                return typedSerializers;
            }
        }
        public override System.Boolean CanSerialize(System.Type type)
        {
            if (type == typeof(global::expirement.X)) return true;
            return false;
        }
        public override System.Xml.Serialization.XmlSerializer GetSerializer(System.Type type)
        {
            if (type == typeof(global::expirement.X)) return new XSerializer();
            return null;
        }
    }
}

1
我同意,我使用数组/列表的组合进行了测试,而不是使用Box,结果相同。数组列表的字符串组合是唯一的不好的组合。数组的数组、列表的数组和列表的列表都可以工作。 - Novaterata
好的。由于您是新手,请不要忘记接受您最喜欢的答案。您可以通过在答案前面勾选复选框来完成此操作。 - Patrick Hofman

0

在尝试序列化之前,尝试将列表转换为数组:

List<Box>[] MainArr = new List<Box>[1];
MainArr[0] = new List<Box>();
Box Box1 = new Box(1);
MainArr[0].Add(Box1);

var arr = Array.ConvertAll(MainArr, x => x.ToArray());

System.Xml.Serialization.XmlSerializer writer = new System.Xml.Serialization.XmlSerializer(arr.GetType());
System.IO.StreamWriter fileWrite = new System.IO.StreamWriter(@"C:\Users\Giorgos\Desktop\ConsoleApplication1\ArrListBox.xml");
writer.Serialize(fileWrite, arr);
fileWrite.Close();

在我的机器上,上述代码会生成以下的xml:

    <?xml version="1.0" encoding="utf-8"?>
<ArrayOfArrayOfBox xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ArrayOfBox>
    <Box>
      <x>1</x>
    </Box>
  </ArrayOfBox>
</ArrayOfArrayOfBox>

0

请注意,在您的StreamWriter中应使用using块(请参见下面代码中的我的注释)。

根据对您问题的评论,这似乎是.NET中的一个错误。我可以看到有几个解决方法:

选项1)使用List<List<Box>而不是List<Box>[]

选项2)覆盖List<T>(或创建自己的IList<T>实现),该实现实现System.Xml.Serialization.IXmlSerializable。我在.NET 3.5和4.5中测试了下面的代码。

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace experiment
{
    public class Box
    {
        public int x;
        public Box(int a)
        {
            x = a;
        }
        public Box()
        {
        }
    }

    public class XmlList<T> : List<T>, IXmlSerializable
    {
        public XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader)
        {
            reader.MoveToContent();
            reader.ReadStartElement();
            if (reader.IsEmptyElement)
                return;
            var ser = new XmlSerializer(typeof(T));
            var nodeType = reader.MoveToContent();
            if (nodeType == XmlNodeType.None)
                return;
            while (nodeType != XmlNodeType.EndElement)
            {
                var item = (T)ser.Deserialize(reader);
                if (item == null)
                    continue;
                Add(item);
                nodeType = reader.MoveToContent();
            }
            reader.ReadEndElement();
        }

        public void WriteXml(XmlWriter writer)
        {
            var ser = new XmlSerializer(typeof(T));
            foreach (T item in this)
            {
                ser.Serialize(writer, item);
            }
        }
    }

    public class Program
    {
        static void Main(string[] args)
        {
            var MainArr = new XmlList<Box>[]
            {
                new XmlList<Box>
                {
                    new Box(1),
                    new Box(4)
                }
            };
            var writer = new XmlSerializer(MainArr.GetType());

            // Make sure to use a 'using' block to ensure that the stream gets closed, even if there was a serialization error.
            using (var fileWrite = new StreamWriter(@"test.xml"))
            {
                writer.Serialize(fileWrite, MainArr);
            }
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接