【问题标题】:How to use XmlInclude to serialize IEnumerable如何使用 XmlInclude 序列化 IEnumerable
【发布时间】:2012-08-24 05:58:31
【问题描述】:

我遇到了使用XmlSerializer 序列化IEnumerable 的问题。由于IEnumerable 表示object 的列表,XmlSerializer 并不提前知道它需要序列化什么类型。但是因为它需要知道,所以当遇到object以外的类型时,它会抛出一个InvalidOperationException

类型 Foo.Bar 不是预期的。使用 XmlInclude 或 SoapInclude 属性指定静态未知的类型。

XmlIncludeAttribute 旨在应用于方法以指示返回值可以是某种类型。但是,IEnumerable 没有我可以添加属性的方法。

我尝试将它们应用于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
}

这并没有解决它,我不知道在哪里可以使用这些属性。

我应该把它们放在哪里?我可以在没有他们的情况下解决它吗?我可以避免编写自己的枚举器吗?

【问题讨论】:

    标签: c# .net serialization xml-serialization ienumerable


    【解决方案1】:

    编辑:由于它们是我之前的回答的几个缺陷 - 没有包含更多条的 bar 并且没有使用 xmlAttributes 这里是我的新解决方案:但是这没有实现......

    编辑:嗯,我已经回顾了一些事情,这是我通过实现 ICollection 的最终解决方案,希望这可以帮助任何试图找到序列化集合的解决方案的人。

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

    输出如下:

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

    另一个堆栈参考:XmlSerializer won't serialize IEnumerable

    【讨论】:

    • IXmlSerializable不要求你自己写所有的序列化代码吗?这对我来说可能是一个真正的痛苦。没有更简单的解决方案吗?
    • 是的类型(T)需要实现IXmlSerializable。使用 Read 和 Write 方法,它们并不难实现,只需说 writer.WriteStartElement("")writer.WriteAttribute("") 等。看看这个:codeproject.com/Articles/43237/…
    • 是的,不应该说真的很容易,因为每个类都可能有相当多的信息要写入 XML 文件。如果要将所有字段写入 XML 文件,还可以循环遍历类的字段。
    • 你有证据证明XmlSerializerWriteXml 方法中有效吗? MSDN 文档让我觉得它没有,因为它提到了序列化文档,而不是元素。
    • 文档和元素是什么意思? - 您传递给WriteXml 方法的XmlWriter writer 是一个Writing 元素。
    猜你喜欢
    • 2010-09-27
    • 1970-01-01
    • 2020-01-17
    • 2017-06-25
    • 2011-01-07
    • 2021-11-10
    • 1970-01-01
    相关资源
    最近更新 更多