在C#开发中,将对象数组序列化为XML是实现数据导出、接口数据传输等功能的常用操作,需要结合System.Xml.Serialization命名空间下的相关类完成,同时需要做好对应的配置并处理可能出现的错误。
基础序列化配置
对象类的特性标注
要让对象数组能够被正确序列化,首先需要给对应的实体类添加必要的特性标注,默认情况下类的公共属性会被序列化,可通过特性调整序列化行为。
using System.Xml.Serialization;
// 标注该类可被序列化,指定XML根节点名称
[XmlRoot("UserList")]
public class User
{
// 指定属性对应的XML元素名称
[XmlElement("UserId")]
public int Id { get; set; }
[XmlElement("UserName")]
public string Name { get; set; }
// 标注该属性不会被序列化
[XmlIgnore]
public string TempData { get; set; }
}
序列化核心代码实现
完成类的配置后,使用XmlSerializer类即可实现对象数组到XML的转换,基础序列化代码如下:
using System;
using System.IO;
using System.Xml.Serialization;
class Program
{
static void Main()
{
// 初始化对象数组
User[] users = new User[]
{
new User { Id = 1, Name = "张三", TempData = "临时数据1" },
new User { Id = 2, Name = "李四", TempData = "临时数据2" }
};
// 创建序列化器,指定要序列化的类型为User数组
XmlSerializer serializer = new XmlSerializer(typeof(User[]));
// 指定输出流,这里输出到控制台
using (StringWriter writer = new StringWriter())
{
serializer.Serialize(writer, users);
string xmlResult = writer.ToString();
Console.WriteLine(xmlResult);
}
}
}
常用可选配置
除了基础特性,还可以根据需求添加更多配置调整序列化结果:
- 指定XML命名空间:通过XmlRoot特性的Namespace属性设置,避免命名冲突
- 处理集合元素名称:使用XmlArray和XmlArrayItem特性指定数组外层节点和内部元素节点名称
- 设置编码格式:创建XmlWriter时指定编码,避免中文乱码问题
指定编码的序列化示例:
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
class Program
{
static void Main()
{
User[] users = new User[]
{
new User { Id = 1, Name = "张三" }
};
XmlSerializer serializer = new XmlSerializer(typeof(User[]));
// 设置编码为UTF-8
XmlWriterSettings settings = new XmlWriterSettings
{
Encoding = Encoding.UTF8,
Indent = true // 格式化输出,增加缩进
};
using (XmlWriter writer = XmlWriter.Create("user_data.xml", settings))
{
serializer.Serialize(writer, users);
}
Console.WriteLine("序列化完成");
}
}
常见错误排查
错误1:对象类型没有无参构造函数
XmlSerializer要求被序列化的类必须有无参构造函数,否则会抛出InvalidOperationException异常。
错误示例:
// 缺少无参构造函数,会导致序列化失败
public class User
{
public User(int id, string name)
{
Id = id;
Name = name;
}
public int Id { get; set; }
public string Name { get; set; }
}
解决方法:给类添加无参构造函数,即使是私有的也可以:
public class User
{
// 添加无参构造函数
public User() { }
public User(int id, string name)
{
Id = id;
Name = name;
}
public int Id { get; set; }
public string Name { get; set; }
}
错误2:序列化非公共属性
XmlSerializer默认只会序列化公共属性和公共字段,如果尝试序列化私有属性会失败。
错误示例:
public class User
{
public User() { }
// 私有属性,无法被序列化
private int Id { get; set; }
public string Name { get; set; }
}
解决方法:将需要序列化的属性设置为公共的,或者通过IXmlSerializable接口自定义序列化逻辑。
错误3:对象包含不可序列化的类型成员
如果对象数组中的类包含不支持XML序列化的类型(如委托、某些泛型类型),会抛出相关异常。
解决方法:给不可序列化的成员添加[XmlIgnore]特性,或者在序列化前将该成员的值转换为可序列化的类型。
错误4:生成的XML中文乱码
如果序列化时没有指定编码,默认可能使用系统编码,导致中文显示乱码。
解决方法:参考前面的编码设置示例,在创建XmlWriter时明确指定编码为UTF-8或者其他需要的编码格式。
错误5:数组序列化后节点名称不符合预期
默认情况下数组会被序列化为外层节点为ArrayOf+类名,内部节点为类名,不符合需求时可以添加XmlArray和XmlArrayItem特性调整。
using System.Xml.Serialization;
[XmlRoot("UserList")]
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
// 包裹数组的容器类
[XmlRoot("AllUsers")]
public class UserContainer
{
// 指定数组外层节点为Users,内部元素节点为User
[XmlArray("Users")]
[XmlArrayItem("User")]
public User[] UserArray { get; set; }
}
序列化UserContainer对象时,就会生成符合预期的XML节点结构。