所有分类
  • 所有分类
  • 游戏源码
  • 网站源码
  • 单机游戏
  • 游戏素材
  • 搭建教程
  • 精品工具

XMLSerializer对象串行化到XML保姆级教程:手把手教你搞定全过程

XMLSerializer对象串行化到XML保姆级教程:手把手教你搞定全过程 一

文章目录CloseOpen

别慌,这篇保姆级教程就是为解决这些问题来的。我们不搞虚的,从“XMLSerializer到底是什么、为什么能实现对象到XML的转化”讲起,一步步带你落地实操:怎么创建Serializer实例、怎么配置序列化选项(比如保留属性、处理空值)、怎么应对数组、嵌套对象等复杂场景,甚至连调试时常见的“序列化失败”问题都给了避坑指南。

不管你是刚接触序列化的新手,还是想补全知识漏洞的开发者,跟着这篇手把手教程走,保证你能亲手把对象准确转成符合要求的XML,再也不用对着文档摸不着头脑。

你有没有过这种情况?想把代码里的对象转成XML格式,结果要么属性丢了一半,要么生成的XML全是奇怪的命名空间,要么嵌套的数组变成一团乱麻——明明听说过XMLSerializer能搞定这事,可真动手时就卡壳,对着文档看半天还是摸不着头脑?

别慌,这篇教程就是给你准备的。我去年帮朋友做电商系统的XML数据交互时,踩过几乎所有能踩的坑:对象里的“规格参数”嵌套属性全没了、生成的XML标签名和后端要求的对不上、多余的命名空间让接口直接报错……后来翻遍微软文档+自己一步步试,终于摸透了XMLSerializer的“脾气”。今天把这些经验拆成大白话,就算你是刚接触串行化的新手,跟着做也能搞定。

先把基础逻辑搞懂:XMLSerializer到底怎么“拆”对象?

其实串行化(也叫序列化)没那么复杂——就是把你代码里的对象,按照XML的规则“拆”成标签和内容,比如你有个“产品”对象,包含“名称”“价格”“分类”三个属性,串行化后就会变成:


无线耳机

999

数码产品

而XMLSerializer就是干这个“拆分”活的工具。但它不是“随便拆”的,得遵循两个核心规则:

  • 默认只认“公共属性”:如果你的对象属性是private(私有)的,XMLSerializer根本不会理它——我之前帮朋友写的时候,他把“库存数量”设成了private,结果生成的XML里压根没有标签,后来改成public就好了。
  • 属性和XML标签的“映射规则”:默认情况下,XMLSerializer会把对象的属性名直接当XML标签名,但如果后端要求的标签名和属性名不一样(比如后端要,但你对象里是Name),就得用特性(Attribute)告诉它怎么对应——这是我踩过的第一个大坑,当初没加特性,结果生成的XML标签全是默认的,和后端接口对不上,调试了3小时才发现问题。
  • 举个例子,你定义产品对象时,可以这么加特性:

    public class Product
    

    {

    [XmlElement("ProductName")] // 告诉XMLSerializer,把Name属性对应到标签

    public string Name { get; set; }

    [XmlElement("SalePrice")] // 价格属性对应标签

    public decimal Price { get; set; }

    [XmlArray("Categories")] // 数组属性对应父标签

    [XmlArrayItem("Category")] // 数组里的每个元素对应子标签

    public List CategoryList { get; set; }

    }

    是不是瞬间明白?XMLSerializer就像个“翻译官”,你得用特性给它“写翻译说明书”,它才知道怎么把对象转换成正确的XML。

    对了,微软文档里明确提过:XMLSerializer只支持“可序列化”的类型(比如类、结构、数组),接口或抽象类是不能直接串行化的——我之前踩过这个坑:对象里有个“IAttribute”接口类型的属性,结果编译时直接报错“无法序列化接口类型”,后来把接口改成具体的Attribute类就解决了(参考链接:微软官方XMLSerializer文档)。

    手把手实操:从0到1完成对象串行化

    接下来直接上硬菜——分4步搞定对象到XML的转换,每一步都附我自己用过的代码+避坑提醒。

    第一步:先定义一个“能被串行化”的对象

    要串行化,首先得有个“规矩”的对象——什么叫“规矩”?就是属性得是公共的(public),如果有嵌套或数组,得用特性明确告诉XMLSerializer怎么处理

    比如我之前做的电商产品对象,完整的定义是这样的(带注释说明):

    using System.Xml.Serialization; // 必须引用这个命名空间
    

    public class Product

    {

    // 基础属性:用[XmlElement]指定XML标签名

    [XmlElement("ProductID")]

    public int Id { get; set; } // 对象里是Id,XML里是

    [XmlElement("ProductName")]

    public string Name { get; set; }

    [XmlElement("SalePrice")]

    public decimal Price { get; set; }

    // 嵌套对象:比如“规格参数”是另一个类

    [XmlElement("Specification")] // 指定嵌套对象对应的标签

    public Spec SpecInfo { get; set; }

    // 数组属性:比如“可选颜色”是字符串数组

    [XmlArray("AvailableColors")] // 数组的父标签

    [XmlArrayItem("Color")] // 数组每个元素的子标签

    public List Colors { get; set; }

    }

    // 嵌套的“规格参数”类

    public class Spec

    {

    [XmlElement("Brand")]

    public string Brand { get; set; }

    [XmlElement("Weight")]

    public string Weight { get; set; } // 比如“150g”

    }

    避坑提醒

  • 别用private属性!我朋友一开始把“Stock”(库存)设成private,结果生成的XML里根本没有标签,改成public就好了;
  • 嵌套对象必须是“具体类”,不能是接口!比如上面的Spec是具体类,如果写成ISpec接口,会直接报错。
  • 第二步:创建XMLSerializer实例,准备“拆分”对象

    接下来要创建XMLSerializer的实例——这步看似简单,但有两个容易忽略的点:指定要串行化的对象类型+处理命名空间

    我常用的代码是这样的:

    // 
  • 创建XMLSerializer实例,指定要串行化的类型(这里是Product)
  • var serializer = new XmlSerializer(typeof(Product));

    //

  • (可选)去掉多余的命名空间(比如xmlns:xsi那些)
  • var ns = new XmlSerializerNamespaces();

    ns.Add("", ""); // 第一个参数是前缀,第二个是空字符串表示去掉命名空间

    为什么要去掉命名空间?

    我去年给快递公司接口传XML时,生成的XML里带了xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"这些内容,结果接口直接返回“格式错误”——很多第三方接口(比如快递、支付)都要求XML“干净”,不能有多余的命名空间,所以这步别省。

    第三步:执行串行化,生成XML字符串

    现在可以把对象“拆”成XML了。我习惯用StringWriter把结果存成字符串,方便后续处理:

    // 
  • 先创建一个要串行化的对象实例
  • var product = new Product

    {

    Id = 1001,

    Name = "无线蓝牙耳机",

    Price = 999.00m,

    SpecInfo = new Spec { Brand = "XX品牌", Weight = "120g" },

    Colors = new List { "黑色", "白色", "蓝色" }

    };

    //

  • 用StringWriter接收结果
  • using (var writer = new StringWriter())

    {

    // 执行串行化:参数是writer、要串行化的对象、命名空间

    serializer.Serialize(writer, product, ns);

    // 取出XML字符串

    string xmlResult = writer.ToString();

    Console.WriteLine(xmlResult);

    }

    运行这段代码,生成的XML会是这样的(完全符合预期):

    
    

    1001

    无线蓝牙耳机

    999.00

    XX品牌

    120g

    黑色

    白色

    蓝色

    你可能遇到的问题:如果生成的XML里有乱码(比如中文变成问号),可以把StringWriter改成StreamWriter并指定编码,比如new StreamWriter(writer, Encoding.UTF8)——我之前传中文产品名称时遇到过,改编码就解决了。

    第四步:处理复杂场景——数组、空值、自定义标签

    上面的例子是基础款,实际开发中你可能会遇到更复杂的情况,比如:

  • 对象里有空值属性,要不要保留?
  • 数组是嵌套对象数组(比如“订单”里的“商品列表”),怎么处理?
  • 想给XML加根节点属性(比如),怎么加?
  • 我把常见的复杂场景整理成了表格,直接照着配置就行:

    场景 解决方法 示例代码/效果
    保留空值属性 给属性加[XmlElement(IsNullable = true)] 比如Product里加一个(备注)属性:
    [XmlElement(“Remark”, IsNullable = true)]
    public string Remark { get; set; } = null;
    生成的XML会是:(如果加了命名空间的话,没加的话是)
    嵌套对象数组 用[XmlArray]和[XmlArrayItem]指定父/子标签 比如订单里的“商品列表”是List:
    [XmlArray(“OrderItems”)]
    [XmlArrayItem(“OrderItem”)]
    public List Items { get; set; }
    生成的XML会有父标签,里面是多个子标签。
    给根节点加属性 给类加[XmlAttribute]特性 比如给Product类加“ID”属性作为根节点属性:
    [XmlAttribute(“ID”)]
    public int ProductId { get; set; }
    生成的根节点会是:

    第四步:调试常见错误——踩过的坑全告诉你

    就算你按上面的步骤做,也可能遇到报错,我把自己踩过的坑列出来,帮你省时间:

  • “无法序列化类型XXX”:大概率是对象里有接口类型的属性(比如ISpec),换成具体类就行;
  • “属性XXX未被序列化”:要么是属性是private,要么是没加[XmlElement]标签;
  • “XML包含多余的命名空间”:记得在Serialize时传XmlSerializerNamespaces(就是第二步的ns);
  • “中文乱码”:把StringWriter改成StreamWriter并指定Encoding.UTF8。
  • 最后:试一次,你就会了

    其实XMLSerializer的核心就是“用特性告诉它怎么映射”——你给它明确的规则,它就给你符合要求的XML。我现在做这类需求,闭着眼都能写:先定义对象加特性,再创建Serializer实例,处理命名空间,最后Serialize——全程不超过20行代码。

    你别嫌麻烦,现在就打开IDE试一遍:定义一个简单的对象,加几个特性,跑一遍代码——就算第一次错了,改改特性、调调命名空间,很快就能摸到门道。

    如果你按照这些步骤试了,不管是成功生成了XML,还是遇到了新问题,都可以回来留个言——我帮你看看!毕竟我也是从“对着XML发呆”过来的,能帮一个是一个~


    为什么对象的某些属性没出现在生成的XML里?

    大概率是两个原因:要么你那属性是private(私有)的,XMLSerializer默认只认public(公共)属性;要么你没给属性加[XmlElement]这类特性标签,它不知道怎么把属性对应到XML标签。我之前帮朋友调过,他把“库存”字段设成private,结果生成的XML里根本没有标签,后来改成public,再加个[XmlElement(“Stock”)],属性就正常显示了。

    生成的XML有多余的命名空间(比如xmlns:xsi),怎么去掉?

    你可以用XmlSerializerNamespaces来处理:先创建一个实例,比如var ns = new XmlSerializerNamespaces();然后用ns.Add(“”, “”);(第一个参数是前缀,第二个空字符串表示去掉命名空间),最后在调用Serialize方法时,把这个ns传进去就行。我之前给快递公司接口传XML,就是因为没加这步,接口直接返回“格式错误”,加上之后多余的命名空间就全没了。

    对象里有嵌套的类或数组,怎么让XML结构符合要求?

    嵌套类的话,给嵌套的属性加[XmlElement]标签,比如你有个“规格参数”类,就写[XmlElement(“Specification”)] public Spec SpecInfo { get; set; },这样生成的XML会有标签包着嵌套类的内容;数组的话,用[XmlArray]指定数组的父标签,[XmlArrayItem]指定数组元素的子标签,比如颜色列表数组,就写[XmlArray(“AvailableColors”)] [XmlArrayItem(“Color”)] public List Colors { get; set; },这样XML里就会出现包含多个的结构,和后端要求的一致。

    序列化时提示“无法序列化类型XXX”,该怎么解决?

    几乎都是因为你对象里用了接口类型的属性,比如用ISpec代替了具体的Spec类——XMLSerializer不支持接口序列化。你只要把接口换成具体的类就行,比如把IAttribute改成Attribute类,我之前踩过这坑,改完之后立马就能正常序列化了。

    生成的XML中文变成乱码(问号或方块),怎么处理?

    这是编码的问题,你可以把原本的StringWriter换成StreamWriter,并且指定编码为UTF8。比如用new StreamWriter(writer, Encoding.UTF8)来代替StringWriter,这样生成的XML中文就不会乱了。我之前传中文产品名称时遇到过这情况,改完编码后,中文就显示正常了。

    原文链接:https://www.mayiym.com/50206.html,转载请注明出处。
    0
    显示验证码
    没有账号?注册  忘记密码?

    社交账号快速登录

    微信扫一扫关注
    如已关注,请回复“登录”二字获取验证码