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 微软官方文档

posted @ 2020-11-18 20:28  飘零_未知的坚持  阅读(1552)  评论(0编辑  收藏  举报