代码之家  ›  专栏  ›  技术社区  ›  gadpaw

如何创建序列化对象集C#

  •  0
  • gadpaw  · 技术社区  · 9 年前

    有各种类型,在特殊情况下,可以用不同的方式进行配置。如何序列化它们?

    [Serializable]
    [XmlRoot("RootXml", Namespace = "")]
    public class RootXml
    {
        object _schemaVersion;
    
        [XmlElement("SchemaVersion")]
        public object SchemaVersion
        {
            get { return _schemaVersion; }
            set { _schemaVersion = value; }
        }
    
        List<object> _test;
    
        [XmlElement("Test")]
        public List<object> Test
        {
            get { return _test; }
            set { _test = value; }
        }
    
        public RootXml()
        {
    
        }
    }
    

    一、 e.根可以包含不同的对象,并且它们必须被序列化。。。

    我有一个类似这样的xml格式 外观:

    <?xml version="1.0" encoding="windows-1251"?>
    <RootXml>
      <SchemaVersion Number="" />
      <Report Code="">
        <Period Code="" Date="">
          <Source ClassCode="" Code="">
            <Form Code="">
              <Column Num="1" Name="" />
              <Column Num="2" Name="" />
              <Column Num="3" Name="" />         
              <Document>
                <Data code="11" />          
                <Data code="12">
                  <Px Num="1" Value="1" />
                  <Px Num="2" Value="1" />
                  <Px Num="4" Value="2" />
                  <Px Num="5" Value="2" />
                </Data>
                <Data code="13" />
              </Document>
            </Form>
          </Source>
        </Period>
      </Report>
    </RootXml>
    

    其中某些元素可能会发生一些变化(文档、带有标签的文档、带有状态的文档等), 包括在其他中(例如,包含在方案中的报告)。。。并且不知道将来如何改变。

    我想构建一组“格式”,它也将包含各种组件,以供替换。。。 也许出于这个目的,您不应该使用序列化 一组属性,以及处理对象和形成xml的反射(近似于XmlSerializer)???

    1 回复  |  直到 9 年前
        1
  •  0
  •   dbc    9 年前

    您正在尝试使用多态字段序列化和反序列化数据。这里有几个选项:

    1. 如果事先知道多态字段中可能遇到的所有类型,可以使用 attributes 告诉 XmlSerializer 如何序列化和反序列化每个类型。特别是,对于多态字段,应用 [XmlElement("DerivedElementName", Type = typeof(DerivedElementType))] 对于可能遇到的每个派生类型。

      例如,简化 RootXml 类,下面允许序列化两种不同类型的报表:

      [XmlRoot("Report", Namespace = "")]
      public class Report
      {
          [XmlAttribute]
          public string Code { get; set; }
      
          [XmlElement]
          public decimal TotalCost { get; set; }
      }
      
      [XmlRoot("DifferentReport", Namespace = "fuuuu")]
      public class DifferentReport
      {
          public DifferentReport() { }
      
          public DifferentReport(string code, string value)
          {
              this.Code = code;
              this.Value = value;
          }
      
          [XmlAttribute]
          public string Code { get; set; }
      
          [XmlText]
          public string Value { get; set; }
      }
      
      [XmlRoot("RootXml", Namespace = "")]
      public class RootXml
      {
          public RootXml() { }
      
          object _test;
      
          [XmlElement("Report", Type=typeof(Report))]
          [XmlElement("DifferentReport", Type = typeof(DifferentReport))]
          public object Data
          {
              get { return _test; }
              set { _test = value; }
          }
      }
      

      之后,可以对以下两项进行序列化和反序列化:

          var root1 = new RootXml { Data = new Report { Code = "a code", TotalCost = (decimal)101.01 } };
          var root2 = new RootXml { Data = new DifferentReport { Code = "a different code", Value = "This is the value of the report" } };
      

      注意,您可以对多态性使用相同的技术 列表 ,在这种情况下,序列化程序将需要具有指定名称的元素序列:

      [XmlRoot("RootXml", Namespace = "")]
      public class RootXml
      {
          public RootXml() { }
      
          List<object> _test;
      
          [XmlElement("Report", Type=typeof(Report))]
          [XmlElement("DifferentReport", Type = typeof(DifferentReport))]
          public List<object> Data
          {
              get { return _test; }
              set { _test = value; }
          }
      }
      
    2. 如果XML可以是任何东西,但您不知道它可能包含什么(例如,因为您必须从将来的版本反序列化XML,并在不丢失数据的情况下重新序列化它),则可能需要将XML加载到 XDocument 然后使用Linq to XML手动搜索数据。有关如何执行此操作的信息,请参阅此处: Basic Queries (LINQ to XML) .

    3. 您可以采用混合方法,将XML加载到 X文档 ,然后使用 XmlSerializer ,使用以下扩展方法:

      public static class XObjectExtensions
      {
          public static T Deserialize<T>(this XContainer element)
          {
              return element.Deserialize<T>(new XmlSerializer(typeof(T)));
          }
      
          public static T Deserialize<T>(this XContainer element, XmlSerializer serializer)
          {
              using (var reader = element.CreateReader())
              {
                  object result = serializer.Deserialize(reader);
                  if (result is T)
                      return (T)result;
              }
              return default(T);
          }
      
          public static XElement Serialize<T>(this T obj, bool omitStandardNamespaces = true)
          {
              return obj.Serialize(new XmlSerializer(obj.GetType()), omitStandardNamespaces);
          }
      
          public static XElement Serialize<T>(this T obj, XmlSerializer serializer, bool omitStandardNamespaces = true)
          {
              var doc = new XDocument();
              using (var writer = doc.CreateWriter())
              {
                  XmlSerializerNamespaces ns = null;
                  if (omitStandardNamespaces)
                      (ns = new XmlSerializerNamespaces()).Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
                  serializer.Serialize(writer, obj, ns);
              }
              return doc.Root;
          }
      }
      

      然后使用它们找出并反序列化XML的已知部分,如下所示:

          var doc = XDocument.Parse(xml);
          var reportElement = doc.Root.Element("Report");
          if (reportElement != null)
          {
              var report1 = doc.Root.Element("Report").Deserialize<Report>();
              // Do something with the report.
      
              // Create a different report 
              var differentReport = new DifferentReport { Code = report1.Code + " some more code", Value = "This is the value of the report" };
              var differentElement = differentReport.Serialize();
      
              reportElement.AddAfterSelf(differentElement);
              reportElement.Remove();
          }
      
    4. 好的,考虑到您使用的是c#2.0,您可以将Xml加载到 XmlDocument 并按如下所述使用: Process XML Data Using the DOM Model 这是Linq到XML的先驱API,使用起来有点困难,但完全是功能性的。

      您也可以采用混合方法并使用 XmlSerializer 反序列化和重新序列化 XmlDocument 。这里有一些 extension methods 为此目的-- 但由于您使用的是c#2.0 必须 删除 this 关键字 :

      public static class XmlNodeExtensions
      {
          public static XmlElement SerializeToXmlElement<T>(this T o, XmlElement parent)
          {
              return SerializeToXmlElement(o, parent, new XmlSerializer(o.GetType()));
          }
      
          public static XmlElement SerializeToXmlElement<T>(this T o, XmlElement parent, XmlSerializer serializer)
          {
              int oldCount = parent.ChildNodes.Count;
              XPathNavigator navigator = parent.CreateNavigator();
              using (XmlWriter writer = navigator.AppendChild())
              {
                  writer.WriteComment(""); // Kludge suggested here: https://social.msdn.microsoft.com/Forums/en-US/9ff20a3c-913d-4c6f-a18a-c10040290862/how-to-xmlserialize-directly-into-xmldocument?forum=asmxandxml
                  serializer.Serialize(writer, o);
              }
              XmlElement returnedElement = null;
              for (int i = parent.ChildNodes.Count - 1; i >= oldCount; i--)
              {
                  XmlComment comment = parent.ChildNodes[i] as XmlComment;
                  if (comment != null)
                  {
                      parent.RemoveChild(comment);
                  }
                  else
                  {
                      returnedElement = (parent.ChildNodes[i] as XmlElement) ?? returnedElement;
                  }
              }
              return returnedElement;
          }
      
          public static XmlDocument SerializeToXmlDocument<T>(this T o)
          {
              return SerializeToXmlDocument(o, new XmlSerializer(o.GetType()));
          }
      
          public static XmlDocument SerializeToXmlDocument<T>(this T o, XmlSerializer serializer)
          {
              XmlDocument doc = new XmlDocument();
              using (XmlWriter writer = doc.CreateNavigator().AppendChild())
                  serializer.Serialize(writer, o);
              return doc;
          }
      
          public static T Deserialize<T>(this XmlElement element)
          {
              return Deserialize<T>(element, new XmlSerializer(typeof(T)));
          }
      
          public static T Deserialize<T>(this XmlElement element, XmlSerializer serializer)
          {
              using (var reader = new XmlNodeReader(element))
                  return (T)serializer.Deserialize(reader);
          }
      }
      

      给定这些方法,您可以执行以下操作:

          // Load the document from XML
          XmlDocument doc = new XmlDocument();
          doc.LoadXml(xml);
      
          // Find all nodes with name "Report"
          foreach (XmlElement reportNode in doc.SelectNodes("/RootXml/Report"))
          {
              // Deserialize as a Report
              Report report = XmlNodeExtensions.Deserialize<Report>(reportNode);
              // Do something with it 
      
              // Create a new Report, based on the original report.
              DifferentReport differentReport = new DifferentReport(report.Code + " some more code", "This is the value of the report"); ;
              // Add the new report to the children of RootXml
              XmlElement newNode = XmlNodeExtensions.SerializeToXmlElement(differentReport, (XmlElement)reportNode.ParentNode);
          }
      

      正如您所看到的那样,这与Linq to XML非常相似。