Serialization on classes that implement IEnumerator

≯℡__Kan透↙ 提交于 2019-12-24 00:59:59

问题


I have written a program which will serialize and de-serialize, it does this fine (I plan on implementing it on the subclasses once I get it properly working on one). However I have run into trouble when I decided I wanted to be able to iterate through the results using a Foreach.

After this didn't work I to find out had to implement the IEnumerator and IEnumerable interfaces and add the required methods to my class. So I have, and this does allow me to loop through my collections.

The problem starts when I try to combine the two things...

When serializing I originally got this error:

Inner: {"The type ThereIsOnlyRules.Army was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically."}

I added [XmlInclude(typeof(Employee))] to my class to prevent this exception but now first two root elements are called <ArrayofAnyType><AnyType> instead of <ArmyListing><Army>. I can't figure out how to change them back [XmlRoot("whatever")] for some reason has no effect.

When deserializing I get this error {"There is an error in XML document (0, 0)."} Inner: {"Root element is missing."}

I have searched - but it seems like this error can be generated in numerous different ways. I haven't found any solutions that apply to my code (as far as I could tell).

I'd much appreciate some information on the cause or solution to these problems I'm having!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using System.IO;
using System.Collections;

namespace ThereIsOnlyRules
{
[XmlInclude(typeof(Army))]
public class ArmyListing : IEnumerator, IEnumerable
{

    // Fields
    private List<Army> _army;

    // Properties
    [XmlArray("army-category")]
    public List<Army> Army
    {
        get { return _army; }
        set { _army = value; }
    }

    // Public Methods
    public void SerializeToXML(ArmyListing armyListing)
    {
        try
        {
            //armyListing.army.Add(army);

            XmlSerializer serializer = new XmlSerializer(typeof(ArmyListing));
            //XmlSerializer serializer = new XmlSerializer(typeof(ArmyListing), new Type[] { typeof(ArmyListing) });
            TextWriter textWriter = new StreamWriter(@"C:\Test\40k.xml");
            serializer.Serialize(textWriter, armyListing);
            textWriter.Close();
        }
        catch (Exception ex) { }
    }

    #region IEnumerator/IEnumerable req methods
    [XmlIgnore]
    private int position = -1;
    //enumerator & ienumerable
    public IEnumerator GetEnumerator()
    {
        return (IEnumerator)this;
    }

    //enumerator
    public bool MoveNext()
    {
        position++;
        return (position < Army.Count);
    }

    //ienumerable
    public void Reset()
    {
        position = 0;
    }
    [XmlIgnore]
    public object Current
    {
        get { return Army[position]; }
    }

    // Added to prevent Exception
    // To be XML serializable, types which inherit from IEnumerable must have an implementation of Add(System.Object)
    //at all levels of their inheritance hierarchy. ThereIsOnlyRules.ArmyListing does not implement Add(System.Object).
    public void Add(Object fix)
    { }
    #endregion
}

[Serializable]
public class Army// : IEnumerator, IEnumerable
{
    // Fields
    private List<UnitCategory> _unitCategory;
    private string _armyName;

    // Properties
    [XmlArray("unit-category")]
    public List<UnitCategory> UnitCategory
    {
        get { return _unitCategory; }
        set { _unitCategory = value; }
    }

    [XmlAttribute("name")]
    public string ArmyName
    {
        get { return _armyName; }
        set { _armyName = value; }
    }

    //#region IEnumerator/IEnumerable req methods
    //private int position = -1;
    ////enumerator & ienumerable
    //public IEnumerator GetEnumerator()
    //{
    //    return (IEnumerator)this;
    //}

    ////enumerator
    //public bool MoveNext()
    //{
    //    position++;
    //    return (position < UnitCategory.Count);
    //}

    ////ienumerable
    //public void Reset()
    //{
    //    position = 0;
    //}
    //public object Current
    //{
    //    get { return UnitCategory[position]; }
    //}
    //public void Add(Object Army)
    //{ }
    //#endregion
}

[Serializable]
public class UnitCategory// : IEnumerator, IEnumerable
{
    // Fields
    private List<UnitType> _unitType;
    private string _unitCategoryName;

    // Properties
    [XmlArray("unit-type")]
    public List<UnitType> UnitType
    {
        get { return _unitType; }
        set { _unitType = value; }
    }

    [XmlAttribute("name")]
    public string UnitCategoryName
    {
        get { return _unitCategoryName; }
        set { _unitCategoryName = value; }
    }

    //#region IEnumerator/IEnumerable req methods
    //private int position = -1;
    ////enumerator & ienumerable
    //public IEnumerator GetEnumerator()
    //{
    //    return (IEnumerator)this;
    //}

    ////enumerator
    //public bool MoveNext()
    //{
    //    position++;
    //    return (position < UnitType.Count);
    //}

    ////ienumerable
    //public void Reset()
    //{
    //    position = 0;
    //}
    //public object Current
    //{
    //    get { return UnitType[position]; }
    //}
    //public void Add(Object Army)
    //{ }
    //#endregion
}

[Serializable]
public class UnitType// : IEnumerator, IEnumerable
{
    // Fields
    private List<Unit> _unit;
    private string _unitTypeName;

    //Properties
    [XmlArray("unit")]
    public List<Unit> Unit
    {
        get { return _unit; }
        set { _unit = value; }
    }

    [XmlAttribute("name")]
    public string UnitTypeName
    {
        get { return _unitTypeName; }
        set { _unitTypeName = value; }
    }

    //#region IEnumerator/IEnumerable req methods
    //private int position = -1;

    ////enumerator & ienumerable
    //public IEnumerator GetEnumerator()
    //{
    //    return (IEnumerator)this;
    //}

    ////enumerator
    //public bool MoveNext()
    //{
    //    position++;
    //    return (position < Unit.Count);
    //}

    ////ienumerable
    //public void Reset()
    //{
    //    position = 0;
    //}
    //public object Current
    //{
    //    get { return Unit[position]; }
    //}

    //public void Add(Object Army)
    //{ }
    //#endregion
}

[Serializable]
public class Unit
{
    // Fields
    private string _unitName;
    private string _composition;
    private string _weaponSkill;
    private string _ballisticSkill;
    private string _strength;
    private string _initiative;
    private string _toughness;
    private string _wounds;
    private string _attacks;
    private string _leadership;
    private string _savingThrow;
    private string _specialRules;
    private string _dedicatedTransport;
    private string _options;
    private string _armour;
    private string _weapons;

    // Properties
    [XmlAttribute("name")]
    public string UnitName
    {
        get { return _unitName; }
        set { _unitName = value; }
    }

    [XmlAttribute("composition")]
    public string Composition
    {
        get { return _composition; }
        set { _composition = value; }
    }

    [XmlAttribute("weapon-skill")]
    public string WeaponSkill
    {
        get { return _weaponSkill; }
        set { _weaponSkill = value; }
    }

    [XmlAttribute("ballistic-skill")]
    public string BallisticSkill
    {
        get { return _ballisticSkill; }
        set { _ballisticSkill = value; }
    }

    [XmlAttribute("strength")]
    public string Strength
    {
        get { return _strength; }
        set { _strength = value; }
    }

    [XmlAttribute("toughness")]
    public string Toughness
    {
        get { return _toughness; }
        set { _toughness = value; }
    }

    [XmlAttribute("wounds")]
    public string Wounds
    {
        get { return _wounds; }
        set { _wounds = value; }
    }

    [XmlAttribute("initiative")]
    public string Initiative
    {
        get { return _initiative; }
        set { _initiative = value; }
    }

    [XmlAttribute("attacks")]
    public string Attacks
    {
        get { return _attacks; }
        set { _attacks = value; }
    }

    [XmlAttribute("leadership")]
    public string Leadership
    {
        get { return _leadership; }
        set { _leadership = value; }
    }

    [XmlAttribute("saving-throw")]
    public string SaveThrow
    {
        get { return _savingThrow; }
        set { _savingThrow = value; }
    }

    [XmlAttribute("armour")]
    public string Armour
    {
        get { return _armour; }
        set { _armour = value; }
    }

    [XmlAttribute("weapons")]
    public string Weapons
    {
        get { return _weapons; }
        set { _weapons = value; }
    }

    [XmlAttribute("special-rules")]
    public string SpecialRules
    {
        get { return _specialRules; }
        set { _specialRules = value; }
    }

    [XmlAttribute("dedicated-transport")]
    public string DedicatedTransport
    {
        get { return _dedicatedTransport; }
        set { _dedicatedTransport = value; }
    }

    [XmlAttribute("options")]
    public string Options
    {
        get { return _options; }
        set { _options = value; }
    }
}
}

Form

using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.IO;

namespace ThereIsOnlyRules
{
public partial class Form1 : Form
{
    ArmyListing armyListing;
    ArmyListing XmlListing = new ArmyListing();

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        SerializeArmyListings();
    }

    public static void SerializeArmyListings()
    {
        UnitCategory troopsCategory = new UnitCategory
        {
            UnitCategoryName = "Troops",
            UnitType = new List<UnitType>
            {
                new UnitType
                    {
                        UnitTypeName = "Infantry",
                        Unit = new List<Unit>
                            {
                                new Unit
                                    {
                                        Armour = "Chitin",
                                        Attacks = "3",
                                        BallisticSkill = "100",
                                        Composition = "20",
                                        DedicatedTransport = "No",
                                        Initiative = "3",
                                        Leadership = "5",
                                        Options = "8",
                                        SaveThrow = "6+",
                                        SpecialRules = "None",
                                        Strength = "3",
                                        Toughness = "4",
                                        UnitName = "Hornmagant",
                                        Weapons = "Many",
                                        WeaponSkill = "3",
                                        Wounds = "1"                                               
                                    }
                            }
                    }
            }
        };

        Army army = new Army
        {
            ArmyName = "Tyranid",
            UnitCategory = new List<UnitCategory>
        {
            troopsCategory
        }
        };

        ArmyListing armyListing = new ArmyListing
        {
            Army = new List<Army>
            {
                army
            }
        };

        armyListing.SerializeToXML(armyListing);// SerializeToXml(armyListing);
    }

    public ArmyListing DeserializeXml()
    {

        string path = @"C:\Test\40k.xml";

        XmlSerializer serializer = new XmlSerializer(typeof(ArmyListing));
        //XmlSerializer serializer = new XmlSerializer(typeof(ArmyListing), new Type[] { typeof(ArmyListing) });


        StreamReader reader = new StreamReader(path);

        XmlListing = (ArmyListing)serializer.Deserialize(reader);
        reader.Close();

        return XmlListing;

    }

    private void button2_Click(object sender, EventArgs e)
    {
        DeserializeXml();

        ////test
        //foreach (var list in armyListing)
        //{
        //    listBox1.DataSource = list;
        //}

        int xmlcount = XmlListing.Army.Count;
    }

}
}

回答1:


I found remove the implementing of IEnumerator, IEnumerable, then you don't have to use XmlInclude.

The output xml is following which can be deserialized.

<?xml version="1.0" encoding="utf-8"?>
<ArmyListing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <army-category>
    <Army name="Tyranid">
      <unit-category>
        <UnitCategory name="Troops">
          <unit-type>
            <UnitType name="Infantry">
              <unit>
                <Unit name="Hornmagant" composition="20" weapon-skill="3" ballistic-skill="100" strength="3" toughness="4" wounds="1" initiative="3" attacks="3" leadership="5" saving-throw="6+" armour="Chitin" weapons="Many" special-rules="None" dedicated-transport="No" options="8" />
              </unit>
            </UnitType>
          </unit-type>
        </UnitCategory>
      </unit-category>
    </Army>
  </army-category>
</ArmyListing>

Edit: I guess if class implement IEnumerable and IEnumerator. XmlSerialer will use it to enumerate. object Current {} property caused the type is lost. so Anytype shows.

What I suggest is to implement IEnumerable, IEnumerator Following is my test code:

public class ArmyListing :  IEnumerable<Army>, IEnumerator<Army>
{

    // Fields
    private List<Army> _army;

    // Properties
    [XmlArray("army-category")]        
    public List<Army> Army
    {
        get { return _army; }
        set { _army = value; }
    }   

    // Public Methods
    public void SerializeToXML(ArmyListing armyListing)
    {
        try
        {
            //armyListing.army.Add(army);

            XmlSerializer serializer = new XmlSerializer(typeof(ArmyListing));
            //XmlSerializer serializer = new XmlSerializer(typeof(ArmyListing), new Type[] { typeof(ArmyListing) });
            TextWriter textWriter = new StreamWriter(@"C:\Temp\40k.xml");
            serializer.Serialize(textWriter, armyListing);
            textWriter.Close();
        }
        catch (Exception ex) { }
    }

    #region IEnumerator/IEnumerable req methods
    [XmlIgnore]
    private int position = -1;


    // Added to prevent Exception
    // To be XML serializable, types which inherit from IEnumerable must have an implementation of Add(System.Object)
    //at all levels of their inheritance hierarchy. ThereIsOnlyRules.ArmyListing does not implement Add(System.Object).

    public void Add(Army fix)
    {
        if (_army == null)
            _army = new List<Army>();

        _army.Add(fix);
    }
    #endregion            

    public IEnumerator<Army> GetEnumerator()
    {
        return this;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this;
    }

    [XmlIgnore]
    public Army Current
    {
        get { return _army[position]; }

    }

    public void Dispose()
    {

    }

    [XmlIgnore]
    object IEnumerator.Current
    {
        get { return _army[position]; }
    }

    public bool MoveNext()
    {
        position++;
        return (position < Army.Count);
    }

    public void Reset()
    {
        position = 0;
    }
}


来源:https://stackoverflow.com/questions/9285863/serialization-on-classes-that-implement-ienumerator

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