Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
130 views
in Technique[技术] by (71.8m points)

c# - How to serialize List<List<object>>?

Framework is c# .net 4.6.2

I am generating automatic XML classes from XML codes

When I auto generate, it automatically converts as Array[][]

But i want to use it as List<List<>>

And i am sure that my conversation from Array to List causes some serialization error. I think it is about get and set functions. So i need your help to fix this issue

Here the auto generated code piece when i edit > paste special > paste XML as classes

    /// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class OxFordDefinition_perGroup
{

    private string _GroupDescField;

    private string _GroupSenseField;

    private string _GroupGrammerField;

    private OxFordDefinition_perGroup_perMainExample_perSubExample[][] _perMainExampleField;

    /// <remarks/>
    public string _GroupDesc
    {
        get
        {
            return this._GroupDescField;
        }
        set
        {
            this._GroupDescField = value;
        }
    }

    /// <remarks/>
    public string _GroupSense
    {
        get
        {
            return this._GroupSenseField;
        }
        set
        {
            this._GroupSenseField = value;
        }
    }

    /// <remarks/>
    public string _GroupGrammer
    {
        get
        {
            return this._GroupGrammerField;
        }
        set
        {
            this._GroupGrammerField = value;
        }
    }

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

But instead of arrays, i want to use List<List<>>

So i make it like below

        /// <remarks/>
    [System.SerializableAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
    public partial class OxFordDefinition_perGroup
    {

        private string _GroupDescField;

        private string _GroupSenseField;

        private string _GroupGrammerField;

        private  List<List<OxFordDefinition_perGroup_perMainExample_perSubExample>> _perMainExampleField;

        /// <remarks/>
        public string _GroupDesc
        {
            get
            {
                return this._GroupDescField;
            }
            set
            {
                this._GroupDescField = value;
            }
        }

        /// <remarks/>
        public string _GroupSense
        {
            get
            {
                return this._GroupSenseField;
            }
            set
            {
                this._GroupSenseField = value;
            }
        }

        /// <remarks/>
        public string _GroupGrammer
        {
            get
            {
                return this._GroupGrammerField;
            }
            set
            {
                this._GroupGrammerField = value;
            }
        }

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

But this time it gives serialization error when i try to serialize like below

       public static string SerializeXML<T>(this T toSerialize)
    {
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
        StringWriter textWriter = new StringWriter();
        xmlSerializer.Serialize(textWriter, toSerialize);
        return textWriter.ToString();
    }

Here the full code of the XML class

http://pastebin.com/y5B8ENM3

Here the error it gives

enter image description here

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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().


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...