对实现IEnumerator的类进行序列化

本文关键字:序列化 实现 IEnumerator | 更新日期: 2023-09-27 18:24:29

我已经编写了一个程序,它将序列化和反序列化,它做得很好(我计划在子类上正确工作后在子类中实现它)。然而,当我决定能够使用Foreach迭代结果时,我遇到了麻烦。

在这不起作用之后,我发现必须实现IEnumeratorIEnumerable接口,并将所需的方法添加到我的类中。所以我有,这确实让我可以循环浏览我的收藏。

当我试图把这两件事结合起来时,问题就开始了。。。

当序列化时,我最初得到了这个错误:

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

我将[XmlInclude(typeof(Employee))]添加到类中以防止出现此异常,但现在前两个根元素被称为<ArrayofAnyType><AnyType>,而不是<ArmyListing><Army>。由于某种原因,我不知道如何将它们改回[XmlRoot("whatever")]没有效果。

当反序列化时,我得到这个错误{"There is an error in XML document (0, 0)."}内部:{"Root element is missing."}

我已经搜索过了,但这个错误似乎可以通过多种不同的方式产生。我还没有找到任何适用于我的代码的解决方案(据我所知)。

我非常感谢提供一些关于我遇到的这些问题的原因或解决方案的信息!

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

表单

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

对实现IEnumerator的类进行序列化

我发现删除了IEnumerator、IEnumerable的实现,那么就不必使用XmlInclude。

下面是可以反序列化的输出xml。

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

编辑:我想如果类实现IEnumerable和IEnumerator。XmlSerialer将使用它进行枚举。object导致类型丢失的Current{}属性。Anytype显示了这一点。

我的建议是实现IEnumerable,IEnumerator以下是我的测试代码:

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