简体   繁体   English

如何使用XmlInclude序列化IEnumerable

[英]How to use XmlInclude to serialize IEnumerable

I've run into an issue with serializing an IEnumerable with the XmlSerializer . 使用XmlSerializer序列化IEnumerable时遇到了问题。 Since IEnumerable represents a list of object , XmlSerializer doesn't know ahead of time what types it needs to serialize. 由于IEnumerable表示object列表,因此XmlSerializer不知道需要序列化什么类型。 But because it needs to know, it throws an InvalidOperationException when it encounters a type other than object . 但是因为需要知道,所以在遇到object以外的其他类型时会抛出InvalidOperationException

The type Foo.Bar was not expected. 类型Foo.Bar不可预期。 Use the XmlInclude or SoapInclude attribute to specify types that are not known statically. 使用XmlInclude或SoapInclude属性可以指定静态未知的类型。

The XmlIncludeAttribute is intended to be applied to a method to indicate that the return value can be a certain type. XmlIncludeAttribute旨在应用于一种方法,以指示返回值可以是某种类型。 However, IEnumerable has no method that I could put the attribute on. 但是, IEnumerable没有可以将属性放在上面的方法。

I tried applying them to GetEnumerator : 我尝试将它们应用于GetEnumerator

public class Bar : IEnumerable
{
    private List<object> list;

    public Bar()
    {
    }

    [XmlInclude(typeof(Bar))]
    [XmlInclude(typeof(ChildBar))]
    public IEnumerator GetEnumerator()
    {
        return list.GetEnumerator();
    }

    public void Add(Bar bar)
    {
        list.Add(bar);
    }

    public void Add(ChildBar childBar)
    {
        list.Add(childBar);
    }

    // used for deserialization
    public void Add(object o)
    {
        if (o is Bar || o is ChildBar)
        {
            list.Add(o);
        }
    }

    // more irrelevant stuff
}

public class ChildBar
{
    public ChildBar()
    {
    }

    // more irrelevant stuff
}

That didn't solve it, and I have no idea where else to use the attributes. 那并不能解决问题,我也不知道该在哪里使用这些属性。

Where should I put them? 我应该放在哪里? Can I work around it without them? 没有他们,我可以解决它吗? Can I avoid writing my own enumerator? 我可以避免编写自己的枚举器吗?

EDIT: Since their were a couple flaws with my previous answer -didn't have bar containing more bars and didn't use xmlAttributes here is my new solution: This does not implement however... 编辑:由于它们是我先前的回答的几个缺陷-没有包含更多条的条并且不使用xmlAttributes,这是我的新解决方案:但是,这没有实现...

EDIT: Well I've gone back and reviewed some things and this is my final solution by implementing ICollection, hope this helps anyone trying to find a solution to serializing Collections. 编辑:好吧,我回去回顾了一些事情,这是实现ICollection的最终解决方案,希望这对尝试找到序列化Collections的解决方案的所有人有所帮助。

public class Program
{
    static void Main(string[] args)
    {
        var program = new Program();

        program.SerializeObject();
    }

    private int tierIndex = 1;

    public void SerializeObject()
    {
        var barCollection = new BarCollection();
            var bar1 = new Bar() { Name = "bar1" };
            barCollection.Add(bar1);
            var bar2 = new Bar() { Name = "bar2" };
            barCollection.Add(bar2);
                var bar3 = new Bar() { Name = "bar3" };
                bar2.BarCollection.Add(bar3);
                var bar4 = new Bar() { Name = "bar4" };
                bar2.BarCollection.Add(bar4);
            var bar5 = new Bar() { Name = "bar 5" };
            barCollection.Add(bar5);
            var bar6 = new Bar() { Name = "bar 6" };
            barCollection.Add(bar6);
                var bar7 = new Bar() { Name = "bar 7" };
                bar6.BarCollection.Add(bar7);
                    var bar8 = new Bar() { Name = "bar 8" };
                    bar7.BarCollection.Add(bar8);



        var x = new XmlSerializer(typeof(BarCollection));
        x.Serialize(Console.Out, barCollection);

        Console.WriteLine("\n");

        WriteCollection(barCollection);

        Console.ReadLine();
    }

    public void WriteCollection(BarCollection barCollection)
    {
        tierIndex++;

        foreach (Bar bar in barCollection)
        {
            Console.Write(new StringBuilder().Insert(0, "--", tierIndex) + "> ");
            Console.Write(bar.Name + "\n");

            WriteCollection(bar.BarCollection);
        }

        tierIndex--;
    }
}

public class BarCollection : ICollection
{
    private readonly ArrayList barNodes = new ArrayList();

    public Bar this[int index]
    {
        get { return (Bar) barNodes[index]; }
    }

    public void CopyTo(Array a, int index)
    {
        barNodes.CopyTo(a, index);
    }

    public int Count
    {
        get { return barNodes.Count; }
    }

    public object SyncRoot
    {
        get { return this; }
    }

    public bool IsSynchronized
    {
        get { return false; }
    }

    public IEnumerator GetEnumerator()
    {
        return barNodes.GetEnumerator();
    }

    public void Add(Bar bar)
    {
        barNodes.Add(bar);
    }

    public void Add(Object bar)
    {
        barNodes.Add((Bar) bar);
    }
}

public class Bar
{
    [XmlAttribute(AttributeName = "Name")]
    public string Name;

    [XmlArray(ElementName = "BarNodes", IsNullable = true)]
    public BarCollection BarCollection = new BarCollection();
}

Heres the output: 继承人的输出:

<?xml version="1.0" encoding="IBM437"?>
<ArrayOfBar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <Bar Name="bar1">
    <BarNodes />
  </Bar>

  <Bar Name="bar2">
    <BarNodes>
      <Bar Name="bar3">
        <BarNodes />
      </Bar>

      <Bar Name="bar4">
        <BarNodes />
      </Bar>

    </BarNodes>
  </Bar>

  <Bar Name="bar 5">
    <BarNodes />
  </Bar>

  <Bar Name="bar 6">
    <BarNodes>
      <Bar Name="bar 7">
        <BarNodes>
          <Bar Name="bar 8">
            <BarNodes />
          </Bar>

        </BarNodes>
      </Bar>

    </BarNodes>
  </Bar>

</ArrayOfBar>

----> bar1
----> bar2
------> bar3
------> bar4
----> bar 5
----> bar 6
------> bar 7
--------> bar 8

Another Stack Reference: XmlSerializer won't serialize IEnumerable 另一个堆栈参考: XmlSerializer不会序列化IEnumerable

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM