2013-10-24 3 views
3

я сгенерировал переменный ток # класса, используя xsd.exe с этим XML-файлом:Как сериализовать массив объектов в C#?

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

я могу инициализировать объект с данными:

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

Я использую следующее сериализуйте его на диск:

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(); 
    } 
} 

Однако я я получаю следующую ошибку при инициализации инициализации сериализатора:

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

Как сериализовать объект Mary на диск?

ответ

2

Что-то с теми сгенерированными классами.

Проблема происходит потому, что MaryFrank.Joe объявляется как двумерный массив MaryFrankJoeSusan объектов, но он украшен XmlArrayItemAttribute который говорящее сериалайзер, что каждый элемент этого 2D массива имеют тип MaryFrankJoeSusan, когда они, конечно, MaryFrankJoeSusan[].

Если вы измените эту строку в сгенерированные классы:

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

к этому:

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

тогда будет сериализовать без ошибок. Однако вы не получите результаты, которые вы ищете. Вместо этого:

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

вы получите (обратите внимание на дополнительный MaryFrankJoeSusan тег):

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

Реальная проблема, кажется, что инструмент xsd.exe сформировал структуру класса неправильно с самого начала. Он не создает класс в иерархии, чтобы представлять Джо, но вместо этого пытается объединить Джо и Сьюзан вместе, что на самом деле не работает здесь.

Я побежал исходный 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> 

, который выглядит нормально для меня. Затем я взял ту же схему и снова запускал ее через инструмент для создания классов C#. Я ожидал бы получить что-то похожее на это:

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

, но вместо этого я получил те же разбитые классы, которые связаны в этом вопросе. Так что это похоже на ошибку в инструменте xsd для меня.

Чтобы заставить его работать, вы можете использовать ручной закодированы классы, которые я сделал выше, изменения кода инициализации это:

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

--или--

другой альтернативой является изменить xsd. Заменить xs:sequence индикаторов для Frank и Joe элементов с xs:choice вместо, как это:

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

С помощью этой схемы, сгенерированные классы выходят гораздо лучше: есть класс для представления Джо в настоящее время. (Я упростил сгенерированный код здесь и удалены некоторые атрибуты для краткости):

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

код установки затем становится:

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

И мы получим ожидаемый результат:

<?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> 
+0

Фантастический ответ Брайан. Спасибо. Похоже, я вернусь к классу ручной работы, потому что он намного чище. Я тестировал ваше решение выше, и он работает. – TERACytE

Смежные вопросы