zoukankan      html  css  js  c++  java
  • XmlSerializer 序列化总结

     一、汇总

    序列化反序列化例程 参考微软官网 ,所有相关问题理论上都能在里面找到原因。注意里面说到 XmlSerializer new的时候只有俩种方式才不会发生内存泄漏。其余会出现dll不释放的内存泄漏。

    XmlSerializer(Type) 
    XmlSerializer.XmlSerializer(Type, String) 

    1.节点

    碰到的问题,就是1)类节点要重命名 ,后面找到“XmlTypeAttribute”;2)数组定义对象不想数组名占用节点,找到“XmlElementAttribute”;3)类定义默认节点名称,使用“XmlTypeAttribute

    节点/属性重命名,一般方式是  XmlXXXX(XXXXName=“新的节点名”)

    节点参考“Tozhang ”的博客

      

    XmlElement 节点重命名

    XmlRoot 根节点重名称

    XmlArrayList集合添加根节点

    XmlArrayItemList集合中子节点重命名

    [Serializable] 将该类标记为可以序列化类
    [XmlRoot(“root”)]可以指定重新指定xml根节点的名称,若不加这特性,此类在序列化时候,会默认使用类名作为根节点

     [XmlRootAttribute("Slab", IsNullable = false)]

    [XmlElement(“code”)]  
    [XmlIgnore] 此特性是忽略此属性
    [XmlAttribute(“attr”)]   此属性会作为特性在  元素中

     
      [XmlTypeAttribute(TypeName = "Segment")] //设定类的节点名称 是“Segment” public class SegmentXXX {
    ……
      }

    [XmlRootAttribute("MyCity", Namespace="abc.abc", IsNullable=false)]     // 当该类为Xml根节点时,以此为根节点名称。
    public class City

    
    

    [XmlAttribute("AreaName")]    // 表现为Xml节点属性。<... AreaName="..."/>
    public string Name

    
    

    [XmlElementAttribute("AreaId", IsNullable = false)]    // 表现为Xml节点。<AreaId>...</AreaId>
    public string Id

    
    

    [XmlArrayAttribute("Areas")]    // 表现为Xml层次结构,根为Areas,其所属的每个该集合节点元素名为类名。<Areas><Area ... /><Area ... /></Areas>
    public Area[] Areas

    
    

    [XmlElementAttribute("Area", IsNullable = false)]    // 表现为水平结构的Xml节点。<Area ... /><Area ... />... 对比上面就是少掉“Areas”节点,少一次缩进。
    public Area[] Areas

    
    

    [XmlIgnoreAttribute]    // 忽略该元素的序列化。

     

    2. 改变XML序列化的默认值

    参考“yubinfeng ”博客。博客描述很详细,作为第二个示例
    遇到问题,要去除开头的xml语句,并去掉根节点的xml名空间声明。

    /// <summary>
    /// 返回去除节点头部的
    /// </summary>
    /// <param name="filename"></param>
    /// <param name="xtw"></param>
    /// <param name="xmlSN"></param>
    private void ReturnXmlWrite(string filename, out XmlWriter xtw, out XmlSerializerNamespaces xmlSN)
    {
    //设置序序化XML格式
    MemoryStream ms = new MemoryStream();
    XmlWriterSettings xws = new XmlWriterSettings();
    xws.Indent = true; //获取或设置一个值,该值指示是否缩进元素。
    xws.OmitXmlDeclaration = true;//获取或设置一个值,该值指示是否省略XML声明。
    xws.Encoding = System.Text.Encoding.UTF8;//设定编码,读取的时候同样编码,可以省略xml带编码行
    xtw = XmlTextWriter.Create(filename, xws);
    //去掉要结点的 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 属性
    xmlSN = new XmlSerializerNamespaces();
    xmlSN.Add("", "");
    }

    3.反射错误

    3.1 类命和内部成员变量冲突

      执行的时候一直报反射错误。查很久,发现是“同名属性错误”

    /// <summary>
        /// 平板周长定义,必须。逆时针相对于平板边界框的左下角给出坐标
        /// </summary>
        [XmlTypeAttribute(TypeName = "Zone")]
        public class MainZone
        {
           
            [XmlElement(ElementName = "Zone")]
            public Zone unPickZone;
            public SlabZone()
            {
                segments = new Segment[4];
                for (int i = 0; i < 4; i++)
                    segments[i] = new Segment();
                unPickZone = new Zone();
            }
        }
      
    上面代码在执行 = new
    XmlSerializer(Type) 会弹窗报错。
    原因是 "MainZone "关联的属性名“Zone” 和 成员对象的类“Zone”冲突。
    更改方法:俩个里面挑一个重命名为其它。
    
    

    3.2  类Xml类型属性(XmlTypeAttribute)和数组节点属性名冲突(XmlElementAttribute)冲突

        [XmlTypeAttribute(TypeName = "Path")]
                public class SegmentPolyLine
                {
                    /// </summary>
                    [XmlElementAttribute(ElementName = "Segment")]
                    public EdgeDefinition[] segmentPath;
                    ……
                 }
    
    
                [XmlTypeAttribute(TypeName = "Segment")]
                public class CuttingEdgeDefinition
                {
                    [XmlAttribute]
                    public double X1 = 0;
                    [XmlAttribute]
                    public double Y1 = 0; 
                       ……
                }        

            以上在序列化生成对象的时候将报反射错误,进一步是XMl数据类型不能唯一确定。解析:同样的节点数据,可能是对象数组,也可能是单个对象。具体反射哪一类,不能唯一确定

            解决方法:去掉“[XmlElementAttribute(ElementName = "Segment")]” 和“ [XmlTypeAttribute(TypeName = "Segment")]” ,任何一者。解除耦合。

    4. 显示顺序

      变量先输出;属性后输出。

          public class ExportInfo
                {
                    private string code;
                    [XmlAttribute]
                    public string Code
                    {
                        get { return code; }
                        set
                        {
                             code = value;
                        }
                    }
    
                    private string description;
                    [XmlAttribute]
                    public string Description
                    {
                        get { return description; }
                        set
                        { description = value;
                        }
                    }

              [XmlAttribute]
              public int Surface;

    }

    以上定义输出结果是

    <ExportInfo  Surface="6083920" Code="FD210104092902050" Description="XXXXX" />

      "Surface"做如下更改后,按顺序输出。

              private int surface = 0;
                    [XmlAttribute]
                    public int Surface
                    {
                        get { return surface; }
                        set
                        {
                            if (value >= 0)
                                surface = value;
                        }
                    }

    序列化输出结果

    <ExportInfo   Code="FD210104092902050" Description="XXXXX"   Surface="6083920"/>

    5. 注意事项

    yubinfeng  转载过来。

     XML序列化一些注意事项

    (1)要序列化的类必须有默认的构造的构造函数,才能使用XmlSerializer序列化,需要序列化的类都必须有一个无参的构造函数(通过对基础中类和类的实例学习,我们必须知道类不定义构造函数的情况下,会默认生成一个无参数的构造函数);

      补充:如果变量只声明,没有赋值,序列化后是没有对应的节点和属性值。

    (2)索引器、私有字段或只读属性(只读集合属性除外)不能被序列化;

    (3)不想序列化时:当不想序列化一个属性时,使用[System.Xml.Serialization.XmlIgnore]标记,能用于属性;[NonSerializable]应用于属性无效,能用于类,结构体等;

    (4)方法不能被序列化(虽然是废话,但是还是列举出来);

    (5)枚举变量可序列化为字符串,无需用[XmlInclude]

    (6)导出非基本类型对象,都必须用[XmlInclude]事先声明。该规则递归作用到子元素 。可以参考  spacer_robot 

    (7)Attribute中的IsNullable参数若等于false,表示若元素为null则不显示该元素。(针对值类型有效)

    (8)某些类就是无法XML序列化的(即使使用了[XmlInclude])

    比如:

    IDictionary(如HashTable);

    父类对象赋予子类对象值的情况;

    对象间循环引用;

    (9)对于无法XML序列化的对象,可考虑:

    使用自定义xml序列化(实现IXmlSerializable接口);

    实现IDictionary的类,可考虑(1)用其它集合类替代;(2)用类封装之,并提供Add和this函数;

    某些类型需要先经过转换,然后才能序列化为 XML。如XML序列化System.Drawing.Color,可先用ToArgb()将其转换为整数;

    过于复杂的对象用xml序列化不便的话,可考虑用二进制序列化;

    (10)默认构造函数是必须的,因为反序列化本质上使用的是反射,需要默认构造函数来实例化类,如果去掉其中的默认构造函数,则编译没有问题,但运行就会报错。

    尽量不要将比较大的属性放在默认构造函数初始化,那会导致在反序列化时对列表初始化两次:默认构造函数中执行一次,反序列化时从XML文档读取再执行一次。

    以上十点注意,其中前三点,也就是加黑的这几点,是重点要知道的。

    二.引用

    引用来源:1.https://www.cnblogs.com/yubinfeng/p/4631838.html

         2.https://www.cnblogs.com/zhang1f/p/11666930.html

         3.https://www.cnblogs.com/zsh_robot/articles/1323949.html

         4.https://www.cnblogs.com/yukaizhao/archive/2011/07/22/xml-serialization.html  博客里面还有其它方式处理xml

         5.https://docs.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlserializer?view=net-5.0 微软官方文档

  • 相关阅读:
    java框架
    MVC编程模式
    java各版本简单对比
    java设计模式
    ES中TF-IDF算法
    es分词器
    java应用零停机,时间索引重建(reindex)
    Spring源码由浅入深系列一 简介
    Spring源代码解析(收藏)
    spring源码读书笔记
  • 原文地址:https://www.cnblogs.com/PiaoLingJiLu/p/14001979.html
Copyright © 2011-2022 走看看