简体   繁体   English

如何在C#中序列化对象数组?

[英]How to serialize an object array in C#?

I generated ac# class using xsd.exe with this xml file: 我使用xsd.exe和这个xml文件生成了ac#class:

<?xml version="1.0" encoding="UTF-8"?>
<Mary>
    <Frank>
        <Joe>
            <Susan>
                <Stuff>data</Stuff>
            </Susan>
            <Susan>
                <Stuff>data</Stuff>
            </Susan>
        </Joe>
        <Joe>
            <Susan>
                <Stuff>data</Stuff>
            </Susan>
            <Susan>
                <Stuff>data</Stuff>
            </Susan>
        </Joe>
    </Frank>
</Mary>

The C# class that was generated can be viewed here. 可以在此处查看生成的C#类。

I can initialize the object with data: 我可以使用数据初始化对象:

var susan = new MaryFrankJoeSusan(){Stuff = "my data"};
var frank = new MaryFrank(){Joe = new MaryFrankJoeSusan[1][]};
frank.Joe[0] = new MaryFrankJoeSusan[1]{susan};
var mary = new Mary { Items = new MaryFrank[1] { frank } };

I'm using the following to serialize it to disk: 我正在使用以下序列化它到磁盘:

var serializer = new XmlSerializer(typeof(Mary));

using (Stream stream = new FileStream(@"C:\out.xml", FileMode.Create))
{
    var settings = new XmlWriterSettings { Indent = true, NewLineOnAttributes = true, OmitXmlDeclaration = true};
    using (XmlWriter writer = new XmlTextWriter(stream, Encoding.Unicode))
    {
        serializer.Serialize(writer, mary);
        writer.Close();
    }
}

However I am get the following error when the serializer is initialized: 但是,当序列化程序初始化时,我收到以下错误:

error CS0030: Cannot convert type 'MaryFrankJoeSusan[]' to 'MaryFrankJoeSusan'

How do I serialize the entire Mary object to disk? 如何将整个Mary对象序列化为磁盘?

Something is off with those generated classes. 这些生成的类有些东西。

The problem is happening because MaryFrank.Joe is declared as a two-dimensional array of MaryFrankJoeSusan objects, but it is decorated with a XmlArrayItemAttribute which is telling the serializer that each item of that 2D array are of type MaryFrankJoeSusan when they are of course MaryFrankJoeSusan[] . 问题正在发生,因为MaryFrank.Joe被声明为MaryFrankJoeSusan对象的二维数组,但是它用XmlArrayItemAttribute修饰,它告诉序列化程序,当它们当然是MaryFrankJoeSusan时,该2D数组的每个项目都是MaryFrankJoeSusan类型MaryFrankJoeSusan[]

If you change this line in the generated classes: 如果在生成的类中更改此行:

[System.Xml.Serialization.XmlArrayItemAttribute("Susan", typeof(MaryFrankJoeSusan),
 Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)]

to this: 对此:

[System.Xml.Serialization.XmlArrayItemAttribute("Susan", typeof(MaryFrankJoeSusan[]),
 Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)]

then it will serialize without error. 然后它将序列化而不会出错。 However, you won't get the results you are looking for. 但是,您无法获得所需的结果。 Instead of this: 而不是这个:

<Mary>
    <Frank>
        <Joe>
            <Susan>
                <Stuff>my data</Stuff>
            </Susan>
        </Joe>
    </Frank>
</Mary>

you will get this (note the extra MaryFrankJoeSusan tag): 你会得到这个(注意额外的MaryFrankJoeSusan标签):

<Mary>
    <Frank>
        <Joe>
            <Susan>
                <MaryFrankJoeSusan>
                    <Stuff>my data</Stuff>
                </MaryFrankJoeSusan>
            </Susan>
        </Joe>
    </Frank>
</Mary>

The real problem seems to be that the xsd.exe tool has generated the class structure incorrectly to begin with. 真正的问题似乎是xsd.exe工具已经错误地生成了类结构。 It is not creating a class in the heirarchy to represent Joe, but is instead trying to combine Joe and Susan together, which doesn't really work here. 它不是在heirarchy中创建一个代表Joe的类,而是试图将Joe和Susan组合在一起,这在这里并不真正起作用。

I ran your original XML from the question through the tool to generate an XSD schema, and I got this: 我从问题中通过工具运行原始XML来生成XSD架构,我得到了这个:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="Mary" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
  <xs:element name="Mary" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="Frank">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="Joe" minOccurs="0" maxOccurs="unbounded">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element name="Susan" minOccurs="0" maxOccurs="unbounded">
                      <xs:complexType>
                        <xs:sequence>
                          <xs:element name="Stuff" type="xs:string" minOccurs="0" />
                        </xs:sequence>
                      </xs:complexType>
                    </xs:element>
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>

which looks OK to me. 哪个看起来对我好。 Then I took that same schema and ran it through the tool again to generate C# classes. 然后我采用相同的模式并再次运行该工具以生成C#类。 I would have expected to get something similar to this: 我原本期望得到类似的东西:

[Serializable]
[XmlRoot(Namespace = "", ElementName = "Mary")]
public class Mary
{
    [XmlElement("Frank")]
    public Frank[] Frank { get; set; }
}
[Serializable]
public class Frank
{
    [XmlElement("Joe")]
    public Joe[] Joe { get; set; }
}
[Serializable]
public class Joe
{
    [XmlElement("Susan")]
    public Susan[] Susan { get; set; }
}
[Serializable]
public class Susan
{
    [XmlElement("Stuff")]
    public string Stuff { get; set; }
}

but instead I got the same broken classes that you linked in the question. 但相反,我得到了你在问题中链接的相同的破碎类。 So it looks like a bug in the xsd tool to me. 所以它看起来像xsd工具中的一个bug给我。

To get it to work, you can either use the hand-coded classes I made above, changing your initialization code to this: 要使其工作,您可以使用我上面制作的手工编码类,将初始化代码更改为:

var susan = new Susan { Stuff = "my data" };
var joe = new Joe { Susan = new Susan[] { susan } };
var frank = new Frank { Joe = new Joe[] { joe } };
var mary = new Mary { Frank = new Frank[] { frank } };

--OR-- - 要么 -

another alternative is to alter the xsd. 另一种选择是改变xsd。 Replace the xs:sequence indicators for Frank and Joe elements with xs:choice instead, like this: xs:choice替换FrankJoe元素的xs:sequence指示符,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="Mary" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
  <xs:element name="Mary" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="Frank">
          <xs:complexType>
            <xs:choice> <!-- was xs:sequence -->
              <xs:element name="Joe" minOccurs="0" maxOccurs="unbounded">
                <xs:complexType>
                  <xs:choice> <!-- was xs:sequence -->
                    <xs:element name="Susan" minOccurs="0" maxOccurs="unbounded">
                      <xs:complexType>
                        <xs:sequence>
                          <xs:element name="Stuff" type="xs:string" minOccurs="0" />
                        </xs:sequence>
                      </xs:complexType>
                    </xs:element>
                  </xs:choice> <!-- was /xs:sequence -->
                </xs:complexType>
              </xs:element>
            </xs:choice> <!-- was /xs:sequence -->
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>

With this schema, the generated classes come out much better: there is a class to represent Joe now. 使用此模式,生成的类更好:现在有一个类来表示Joe。 (I've simplified the generated code here and removed some of the attributes for brevity): (为了简洁,我在这里简化了生成的代码并删除了一些属性):

[System.SerializableAttribute()]
[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)]
public partial class Mary {
    [System.Xml.Serialization.XmlElementAttribute("Frank", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public MaryFrank[] Items { get; set; }
}

[System.SerializableAttribute()]
public partial class MaryFrank {
    [System.Xml.Serialization.XmlElementAttribute("Joe", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public MaryFrankJoe[] Items { get; set; }
}

[System.SerializableAttribute()]
public partial class MaryFrankJoe {
    [System.Xml.Serialization.XmlElementAttribute("Susan", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public MaryFrankJoeSusan[] Items { get; set; }
}

[System.SerializableAttribute()]
public partial class MaryFrankJoeSusan {
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string Stuff { get; set; }
}

The setup code then becomes: 然后设置代码变为:

var susan = new MaryFrankJoeSusan() { Stuff = "my data" };
var joe = new MaryFrankJoe() { Items = new MaryFrankJoeSusan[] { susan } };
var frank = new MaryFrank() { Items = new MaryFrankJoe[] { joe } };
var mary = new Mary { Items = new MaryFrank[] { frank } };

And we get the expected output: 我们得到了预期的输出:

<?xml version="1.0" encoding="utf-16"?>
<Mary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Frank>
        <Joe>
            <Susan>
                <Stuff>my data</Stuff>
            </Susan>
        </Joe>
    </Frank>
</Mary>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM