Сериализация на классах, которые реализуют IEnumerator - PullRequest
2 голосов
/ 15 февраля 2012

Я написал программу, которая будет сериализовать и десериализовать, она прекрасно работает (я планирую реализовать ее на подклассах, как только я правильно ее проработаю).Однако у меня возникли проблемы, когда я решил, что хочу иметь возможность перебирать результаты, используя 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)."} Внутренний: {"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;
    }

}
}

1 Ответ

1 голос
/ 15 февраля 2012

Я обнаружил, что удалил реализацию 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>

Edit: Я думаю, если класс реализует IEnumerable и IEnumerator. XmlSerialer будет использовать его для перечисления. Свойство объекта 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;
    }
}
...