Сериализация в классах, реализующих IEnumerator

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

После того, как это не сработало, мне пришлось реализовать интерфейсы IEnumerator и IEnumerable и добавить необходимые методы в мой класс. Так что у меня есть, и это позволяет мне просматривать мои коллекции.

Проблема начинается, когда я пытаюсь объединить две вещи...

При сериализации я изначально получил эту ошибку:

Внутренний: {"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)."} Inner: {"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;
    }

}
}

person Amicable    schedule 14.02.2012    source источник
comment
Пожалуйста, посмотрите Edit: часть моего ответа.   -  person findcaiyzh    schedule 15.02.2012


Ответы (1)


Я обнаружил, что удалите реализацию 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 Текущее свойство {} привело к потере типа. так 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;
    }
}
person findcaiyzh    schedule 15.02.2012
comment
Я могу подтвердить, что это позволяет сериализации работать, однако это вызывает исключение NullReferenceException при попытке десериализации. Возвращенный объект не заполняется, его счетчик равен 0, а Current генерирует исключение nullException. Пробовал тег XmlIgnore для Current без всякой радости, все еще имея скрипку. - person Amicable; 15.02.2012
comment
Метод добавления важен, см. мою пересмотренную реализацию public void Add (армейское исправление) - person findcaiyzh; 15.02.2012
comment
Ах, мой плохой. Я заметил, что вы изменили тип метода добавления, и я думал, что реализовал это изменение. Все работает! Большое спасибо :) - person Amicable; 15.02.2012