序列化派生类型的派生类型属性的数组

时间:2017-08-30 15:56:34

标签: c# serialization xml-serialization

我有一个简单的.Net框架C#控制台应用程序,它序列化一个派生类型的类,其中属性也是派生类型。

派生类的名称与基类相同,但它们位于不同的名称空间中以防止它们发生冲突。虽然XmlSerializer使用的反射似乎并不适用于此。也许有一些方法可以纠缠我仍然可以使用漂亮名称的基类(因为它在使用时将是一个DLL接口),并且XML也使用漂亮的名称(因为它将是人类可编辑的)。 。派生类的漂亮名称不是必需的(尽管会是奖金)。

希望XML看起来像:

<?xml version="1.0" encoding="utf-8"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Details>
    <Detail>
      <Description>bald</Description>
    </Detail>
    <Detail>
      <Description>red tie</Description>
    </Detail>
  </Details>
</Person>

但是我能得到的最接近的是<Detail>元素

    <Detail xsi:type="DerivedDetail"> ... </Detail>

必须添加此xs:type属性不适合人工可编辑的XML。

这是通过以下C#代码实现的。如果我删除标记的XmlType属性,那么元素应该序列化而没有xsi:type属性,但我得到一个例外:

  

InvalidOperationException:Types&#39; Test.Detail&#39;和&#39; Test.Xml.Detail&#39;两者都使用来自命名空间的XML类型名称&#39; Detail&#39;&#39;。使用XML属性为类型指定唯一的XML名称和/或命名空间。

我尝试将派生的Xml.Detail类标记为匿名XML类型,但是异常读取:

  

InvalidOperationException:不能包含匿名类型&#39; Test.Xml.Detail&#39;。

我已经阅读了许多类似的问题,但还没有遇到任何可以解决这个问题的问题。

在下面的代码中,Person是一个抽象类,其属性是抽象类型Detail的数组。这些类型分别由Xml.PersonXml.Detail派生。该程序创建一个测试Xml.Person对象并尝试序列化它:

using System;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create test details array
            var TestDetails = new Xml.Detail[] 
            {
                new Xml.Detail
                {
                    Description = "bald"
                },
                new Xml.Detail
                {
                    Description = "red tie"
                }
            };

            // create test person object that holds details array
            var TestBar = new Xml.Person()
            {
                Details = TestDetails
            };

            // serialize the person object
            var s = new Xml.Serializer();
            var TestOutput = s.Serialize(TestBar);

            Console.WriteLine(TestOutput);
        }
    }

    // base classes
    public abstract class Person
    {
        public abstract Detail[] Details { get; set; }
    }

    public abstract class Detail
    {
        public abstract string Description { get; set; }
    }

    namespace Xml
    {
        // derived classes
        [Serializable]
        [XmlType(AnonymousType = true)]
        [XmlRoot(IsNullable = false)]
        public class Person : Test.Person
        {
            [XmlArrayItem("Detail", typeof(Detail))]
            [XmlArray(IsNullable = false)]
            public override Test.Detail[] Details { get; set; }
        }

        // This attribute makes serialization work but also adds the xsi:type attribute
        [XmlType("DerivedDetail")]
        [Serializable]
        public class Detail : Test.Detail
        {
            public override string Description { get; set; }
        }

        // class that does serializing work
        public class Serializer
        {
            private static XmlSerializer PersonSerializer = 
                new XmlSerializer(typeof(Person), new Type[] { typeof(Detail) });

            public string Serialize(Test.Person person)
            {
                string Output = null;
                var Stream = new MemoryStream();
                var Encoding = new UTF8Encoding(false, true);

                using (var Writer = new XmlTextWriter(Stream, Encoding))
                {
                    Writer.Formatting = Formatting.Indented;
                    PersonSerializer.Serialize(Writer, person);
                    Output = Encoding.GetString(Stream.ToArray());
                }
                Stream.Dispose();
                return Output;
            }
        }
    }
}

1 个答案:

答案 0 :(得分:1)

Not sure why you're using base classes instead of interfaces when you don't have any member fields. Regardless, I assumed you wanted None to be a concrete instantiation of abstract Col1 Col2 Col3 Col4 Col5 Col6 Col7 1 Shop1 Mon open 6am Close 4pm 2 Shop1 Tue Open 6am Close 5pm 3 shop1 Wed Open 6am Close 4pm 4 Shop2 Mon open 10am Close 3pm 5 Shop2 Tue open 11am Close 2pm or any classes derived from abstract Col1 Col2 Col3 Col4 Col5 Col6 Col7 col8 col9 col10 Col11 Col12 1 Shop1 Mon open 6am Close 4pm Tue Open 6am Close 5pm 2 Shop2 Mon open 10am close 4pm Tue open 11am close 2pm without decorating abstract Xml.Person with XML attributes. I accomplished this by forcing abstract Person to become a concrete instantiation of Person before serializing it. Please replace Person with Person.

Xml.Person