如何创建序列化对象的集合C# [英] How to create sets of the serialized objects C#

查看:82
本文介绍了如何创建序列化对象的集合C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

There are various types, in a special case which can be configured in different ways. How to serialize them?

[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()
    {

    }
}

即根可以包含不同的对象,并且必须将它们序列化...

I.e. root can include different objects, and they have to be serialized...

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

I have a xml-format approximately of such look:

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

其中某些元素可能会有所变化(文档,带标签的文档,带状态的文档等) ),
包含在其他项目中(例如,报告中包含计划)……并且不知道将来如何更改。

In which some elements can change a little (Document, Document with tags, Document with the status, etc.), included in others (for example, report incl. in scheme) ... and do not know how to change in the future.

I想要构造一组也将具有各种组成部分的格式,以供替换...
也许为此目的,您不应该使用序列化,并定义
属性集,以及反射以处理对象并形成xml(大约与XmlSerializer一样)?

I want to construct a set of "formats" which will also have various components, to be substituted... Maybe for this purpose you shouldn't use serialization, and to define set of attributes, and a reflection to process objects and to form xml (approximately just as XmlSerializer)???

推荐答案

您正在尝试序列化和反序列化数据具有多态字段。您在这里有一些选择:

You are trying to serialize and deserialize data with polymorphic fields. You have a few options here:


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

  1. If you know in advance all possible types that might be encountered in a polymorphic field, you can use attributes to tell XmlSerializer how to serialize and deserialize each type. In particular, for a polymorphic field, apply [XmlElement("DerivedElementName", Type = typeof(DerivedElementType))] for every derived type that might be encountered.

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

For instance, simplifying your RootXml class somewhat, the following allows for two different types of report to be serialized:

[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; }
    }
}

然后,下面两个都可以序列化和反序列化:

And then later, both of the following can be serialized and deserialized:

    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" } };

请注意,您可以对多态列表使用相同的技术,其中如果序列化程序期望具有指定名称的元素序列:

Note that you can use the same technique with polymorphic lists, in which case the serializer will expect sequences of elements with the specified names:

[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; }
    }
}


  • 如果XML可以是您不知道其中可能包含什么(例如,因为必须从将来的版本中反序列化XML并重新序列化而不会造成数据丢失),因此可能需要将XML加载到 XDocument 然后使用Linq-to-XML手动搜索数据。有关如何执行此操作的信息,请参见此处:基本查询(LINQ to XML)

    您可以采用混合方法,将XML加载到 XDocument 中,然后使用以下扩展方法使用 XmlSerializer 反序列化并序列化熟悉的部分:

    You could adopt a hybrid approach where you load the XML into an XDocument, then deserialize and serialize familiar portions with XmlSerializer, using the following extension methods:

    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如下:

    Then use them to pick out and deserialize known portions of your XML as follows:

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


  • 好,如果您使用的是c#2.0,则可以加载您的Xml放入 XmlDocument 并按此处所述使用它:使用DOM模型处理XML数据。这是Linq-to-XML的原始API,使用起来有点困难-但尽管如此,它仍然可以正常工作。

  • OK, given that you are using c# 2.0, you can load your Xml into an XmlDocument and use it as described here: Process XML Data Using the DOM Model. This is a precursor API to Linq-to-XML and is somewhat harder to work with -- but nevertheless totally functional.

    您还可以采用混合方法并使用 XmlSerializer 来反序列化并重新序列化 XmlDocument 的已知块。这是一些扩展方法,用于此目的-您使用的是c#2.0,您必须删除关键字

    You can also adopt the hybrid approach and use XmlSerializer to deserialize and re-serialize known chunks of an XmlDocument. Here are some extension methods for this purpose -- but since you're using c# 2.0, you must remove the this keyword:

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

    使用这些方法,您可以执行以下操作:

    Given those methods, you can do things like:

        // 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。

    As you can see this is quite similar to what is possible with Linq-to-XML.

    这篇关于如何创建序列化对象的集合C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆