How to serialize List<List<object>>?

巧了我就是萌 提交于 2019-11-28 14:52:27

Actually neither your original nor your modified OxFordDefinition_perGroup can be serialized successfully. The problem is your value for XmlArrayItem.Type, which is the second argument to the constructor:

[System.Xml.Serialization.XmlArrayItemAttribute("_perSubExample", typeof(OxFordDefinition_perGroup_perMainExample_perSubExample), IsNullable = false)]
public OxFordDefinition_perGroup_perMainExample_perSubExample[][] { get; set; }

According to the docs

Use the Type property to specify an overridden type for a public field or public read/write property value.

If a field or property returns an array of type Object, apply multiple instances of the XmlArrayItemAttribute to the field or property. For each instance, set the Type property to a type of object that can be inserted into the array.

The typeof(OxFordDefinition_perGroup_perMainExample_perSubExample) indicates that items in the outermost collection will be of type typeof(OxFordDefinition_perGroup_perMainExample_perSubExample). However, in fact the items in the array or list are of type OxFordDefinition_perGroup_perMainExample_perSubExample[] or List<OxFordDefinition_perGroup_perMainExample_perSubExample> respectively, which cannot, of course, be assigned to this type. This XmlSerializer code generation fails.

If you remove the type setting entirely from your [XmlArrayItem] attribute then both versions of your type will be serializable to XML:

[System.Xml.Serialization.XmlArrayItemAttribute("_perSubExample", IsNullable = false)]
public List<List<OxFordDefinition_perGroup_perMainExample_perSubExample>> _perMainExample
{
    get
    {
        return this._perMainExampleField;
    }
    set
    {
        this._perMainExampleField = value;
    }
}

Sample fiddle.

Update

You asked, it adds extra layer which should not exists. any idea?

This is because you are using nested lists or jagged arrays. Change it to be a simple list or 1-d array:

private List<OxFordDefinition_perGroup_perMainExample_perSubExample> _perMainExampleField;

/// <remarks/>
[System.Xml.Serialization.XmlArrayItemAttribute("_perSubExample", IsNullable = false)]
public List<OxFordDefinition_perGroup_perMainExample_perSubExample> _perMainExample
{
    get
    {
        return this._perMainExampleField;
    }
    set
    {
        this._perMainExampleField = value;
    }
}

Sample fiddle #2.

I then downloaded the entire XML from http://pastebin.com/raw/BJhRfFNf and ran xsd.exe to generate a schema, and then classes, from the XML, and I was able to reproduce your problem - incorrect classes were generated. I then manually changed the jagged array to a flat array (a List<T> would work fine also) and was able to serialize and deserialize the XML without an exception getting thrown:

Sample fiddle #3.

Unfortunately, it appears that only the first </_perMainExample> node is successfully deserialized using these tweaked classes, so at this point this auto-generated code just doesn't seem viable.

I'm not sure why xsd.exe generated bad code here, you might want to ask another question or open an issue with Microsoft.

Final Update

It looks as though xsd.exe (and thus Paste XML as Classes) is having trouble with a repeating element that contains nested repeating elements:

<_perMainExample>
  <_perSubExample>
  </_perSubExample>

  <_perSubExample>
  </_perSubExample>
</_perMainExample>

<_perMainExample>
  <_perSubExample>
  </_perSubExample>

  <_perSubExample>
  </_perSubExample>
</_perMainExample>

I'm not sure what the problem is, but at this point I recommend switching to a different code-generation tool such as https://xmltocsharp.azurewebsites.net/, which generates the following classes:

[XmlRoot(ElementName="_Example")]
public class _Example {
    [XmlElement(ElementName="_SenseNot")]
    public string _SenseNot { get; set; }
    [XmlElement(ElementName="_GrammaticNot")]
    public string _GrammaticNot { get; set; }
    [XmlElement(ElementName="_Desc")]
    public string _Desc { get; set; }
}

[XmlRoot(ElementName="_perSubExample")]
public class _perSubExample {
    [XmlElement(ElementName="_UpperTitle")]
    public string _UpperTitle { get; set; }
    [XmlElement(ElementName="_FormGroup")]
    public string _FormGroup { get; set; }
    [XmlElement(ElementName="_SenseNot")]
    public string _SenseNot { get; set; }
    [XmlElement(ElementName="_GrammaticNot")]
    public string _GrammaticNot { get; set; }
    [XmlElement(ElementName="_Desc")]
    public string _Desc { get; set; }
    [XmlElement(ElementName="_Example")]
    public List<_Example> _Example { get; set; }
    [XmlElement(ElementName="_Synonyms")]
    public string _Synonyms { get; set; }
}

[XmlRoot(ElementName="_perMainExample")]
public class _perMainExample {
    [XmlElement(ElementName="_perSubExample")]
    public List<_perSubExample> _perSubExample { get; set; }
}

[XmlRoot(ElementName="_perGroup")]
public class _perGroup {
    [XmlElement(ElementName="_GroupDesc")]
    public string _GroupDesc { get; set; }
    [XmlElement(ElementName="_GroupSense")]
    public string _GroupSense { get; set; }
    [XmlElement(ElementName="_GroupGrammer")]
    public string _GroupGrammer { get; set; }
    [XmlElement(ElementName="_perMainExample")]
    public List<_perMainExample> _perMainExample { get; set; }
}

[XmlRoot(ElementName="OxFordDefinition")]
public class OxFordDefinition {
    [XmlElement(ElementName="sourceURL")]
    public string SourceURL { get; set; }
    [XmlElement(ElementName="originDesc")]
    public string OriginDesc { get; set; }
    [XmlElement(ElementName="_perGroup")]
    public List<_perGroup> _perGroup { get; set; }
}

Notice that:

  1. The code generated is much, much cleaner.

  2. An extra level of class _perMainExample is added to encapsulate the inner _perSubExample list.

Sample fiddle #4 which shows that the original and re-serialized XML are identical by calling XNode.DeepEquals().

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!