【问题标题】:.NET XML Serialization and inheritance.NET XML 序列化和继承
【发布时间】:2010-12-15 02:25:20
【问题描述】:

我有这样的结构:

public interface A
{
    public void method();
}

public class B : A
{
}

public class C : A
{
}

List<A> list;

List 包含 B 和 C 类型的对象,它们还有一些我想保留的字段,我现在可以对其进行序列化、反序列化并获取正确的对象实例吗? 最好是XML

编辑:

有没有什么简单的方法可以序列化这个包含接口的列表,然后反序列化回B和C实例?

【问题讨论】:

    标签: c# inheritance serialization xml-serialization


    【解决方案1】:

    假设您使用的是内置的 .net XML 序列化,您应该查看以下属性:

    System.Xml.Serialization.XmlIncludeAttribute
    

    它允许您在序列化/反序列化时指示序列化程序包含其他类型。

    向列表中添加新类型而不更新序列化元数据是常见的错误来源,请确保您有足够的测试覆盖率。

    【讨论】:

      【解决方案2】:

      我会使用抽象类而不是接口(因为无法序列化接口类型),然后不是使用 XmlInclude 属性对类型进行硬编码,而是将已知类型添加到 Serial 和 Deserialize 中的 XmlSerializer像这样的方法:

          string listXml = Serialize<List<A>>(ListA, new Type[] { typeof(B), typeof(C) });
      
          List<IA> NewList = Deserialize<List<A>>(listXml, new Type[] { typeof(B), typeof(C) });
      
          private static T Deserialize<T>(string Xml, Type[] KnownTypes)
          {
              XmlSerializer xs = new XmlSerializer(typeof(T),KnownTypes);
      
              StringReader sr = new StringReader(Xml);
              return (T)xs.Deserialize(sr);
          }
      
          private static string Serialize<T>(Object obj, Type[] KnownTypes)
          {
              StringBuilder sb = new StringBuilder();
              using (StringWriter sw = new StringWriter(sb))
              {
                  XmlSerializer xs = new XmlSerializer(typeof(T), KnownTypes);
      
                  xs.Serialize(sw, obj);
              }
              return sb.ToString();
          }
      

      【讨论】:

        【解决方案3】:

        您可以尝试使用DataContractSerializer:

        public interface A
        {
        }
        
        public class B : A
        {
        }
        
        public class C : A
        {
        }
        
        class Program
        {
            static void Main(string[] args)
            {
                List<A> list = new List<A>(new A[] { new B(), new C() });
                var serializer = new DataContractSerializer(
                    list.GetType(), new[] { typeof(B), typeof(C) });
        
                var sb = new StringBuilder();
                using (var stringWriter = new StringWriter(sb))
                using (var writer = XmlWriter.Create(stringWriter))
                {
                    serializer.WriteObject(writer, list);
                }
        
                using (var stringReader = new StringReader(sb.ToString()))
                using (var reader = XmlReader.Create(stringReader))
                {
                    list = (List<A>)serializer.ReadObject(reader);
                }
        
            }
        }
        

        【讨论】:

          【解决方案4】:

          是的,但是您必须使用 XmlElement、XmlRoot 和 XmlArray 属性。 每种类型都需要自己的元素名称。

          编辑:一些示例代码。所有类都派生自一个公共基类。

          这是一个示例代码:

          [XmlRoot(ElementName="Root")]
          public sealed class SomeObject
          {
          
              private BaseObject _Object;
          
              [XmlElement(Type=typeof(App.Projekte.Projekt), ElementName="Projekt")]
              [XmlElement(Type=typeof(App.Projekte.Task), ElementName="Task")]
              [XmlElement(Type=typeof(App.Projekte.Mitarbeiter), ElementName="Mitarbeiter")]
              public BaseObject Object
              {
                  get
                  {
                      return _Object;
                  }
                  set
                  {
                      _Object = value;
                  }
              }
          }
          

          编辑:删除序列化属性,因为它不需要(但在我的代码所在的项目中需要)

          【讨论】:

          • 你不需要[Serializable]。 XML 序列化不使用它。
          【解决方案5】:

          根据您的情况,创建一个实现您的接口的抽象类,例如:

          abstract class Abs : A
          

          然后从 Abs 派生你的类

          public class B : Abs
          public class C : Abs
          

          和 列表列表;

          现在使用 XmlIncludeAttribute 将您的类型添加到 XmlSerializer 的类型数组中。

          【讨论】:

            【解决方案6】:

            XmlSerializer 不适用于接口。所以你可以:

            将接口转换为抽象类,然后为其使用XmlIncludeAttribute 或将KnownTypes 提供给XmlSerializer

            为父类型实现IXmlSerializable

            考虑使用 .NET 3.0 中的 DataContractSerializer

            【讨论】:

              猜你喜欢
              • 2010-09-06
              • 1970-01-01
              • 2012-12-01
              • 2012-11-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多