在C#开发中,经常需要把程序里的List集合保存成XML文件,或者通过网络传给其他系统。相比手动拼接字符串,使用框架自带的序列化机制不仅代码简洁,还能自动处理特殊字符和编码问题。下面介绍几种常用的转换方式,并分析它们的适用场景。

使用XmlSerializer进行标准序列化
XmlSerializer是.NET基础类库提供的经典序列化工具,它可以将带有公共属性和无参构造函数的对象图转换成符合XML规范的文件。这种方式最明显的优势是类型安全,编译器能帮我们检查数据结构,且输出的XML结构清晰,便于其他语言解析。
要注意的是,被序列化的类不能是匿名类型,字段必须暴露为public的get和set访问器,否则序列化器会忽略它们。另外默认序列化会带上程序集相关的命名空间,我们可以通过XmlRoot等特性自定义根节点名称。
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
}
class Program
{
static void Main()
{
List<Student> list = new List<Student>
{
new Student { Name = "张三", Age = 20 },
new Student { Name = "李四", Age = 22 }
};
XmlSerializer serializer = new XmlSerializer(typeof(List<Student>), new XmlRootAttribute("Students"));
using (StringWriter writer = new StringWriter())
{
serializer.Serialize(writer, list);
string xml = writer.ToString();
Console.WriteLine(xml);
}
}
}
上面的代码会输出一个以Students为根节点、每个Student作为子元素的XML文档。如果希望控制某个字段在XML中的名字,可以在属性上添加[XmlElement("学生姓名")]这样的特性,序列化器会按特性中的名称写入节点。
这种方案的缺点是对于复杂嵌套对象配置稍显繁琐,且不支持字典等部分集合类型的直接序列化。但在大多数业务系统间的数据交换中,它已经足够稳定和高效。
利用LINQ to XML手动构建
当我们需要完全掌控XML结构,比如要给不同节点加特定命名空间、属性,或者数据源本身就是异构的时候,可以使用System.Xml.Linq下的XDocument来手动从List生成XML。这种方法灵活度最高,写起来也直观。
手动构建不要求实体类有公共 setter,因为我们只是读取数据然后拼装,而不是依靠反射映射。不过代价是需要自己处理空值和字符转义,好在XElement在赋值时已经内部处理了特殊符号,比用字符串拼接安全得多。
using System;
using System.Collections.Generic;
using System.Xml.Linq;
public class Product
{
public string Title;
public decimal Price;
}
class Demo
{
static void Main()
{
List<Product> products = new List<Product>
{
new Product { Title = "键盘", Price = 99.9m },
new Product { Title = "鼠标", Price = 49.5m }
};
XDocument doc = new XDocument(
new XElement("Products",
products.ConvertAll(p =>
new XElement("Product",
new XAttribute("Price", p.Price),
new XElement("Title", p.Title)
)
)
)
);
Console.WriteLine(doc.ToString());
}
}
该方式输出的XML中,Price作为Product节点的属性,Title作为子元素。由于使用了XElement和XAttribute,即使Title里包含&或者<符号,框架也会自动转义,不会出现格式错误的XML。
在需要生成带命名空间或者混合内容的报文时,LINQ to XML比XmlSerializer更容易微调。但如果结构非常标准且稳定,手写代码会增加维护成本,此时还是序列化更省心。
借助Json.NET再间接转换
有些团队项目中已经广泛使用了Newtonsoft.Json,那么也可以先把List序列化为JSON,再利用JsonConvert的DeserializeXNode方法转成XML。这在已有JSON工具链、又临时需要XML格式的场景下非常快捷。
这种间接方案的好处是能序列化匿名对象,因为JSON本身不要求严格类定义。但要注意JSON到XML的映射规则:数组会变成带Item的子节点,属性名也可能和预期不一致,需要后续处理。
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
class Test
{
static void Main()
{
var data = new List<object>
{
new { Id = 1, Name = "测试" },
new { Id = 2, Name = "样例" }
};
string json = JsonConvert.SerializeObject(data);
var xml = JsonConvert.DeserializeXNode(json, "Root");
Console.WriteLine(xml.ToString());
}
}
运行后会得到以Root为父节点、每个对象作为Item元素的XML。如果对接方对节点名称敏感,还需要手动改节点名,因此只建议作为临时或内部转换手段。
从性能角度看,多一次JSON中转会带来额外开销,高频调用时应优先选择前两种原生方案。综合来看,明确实体结构用XmlSerializer,灵活拼装用LINQ to XML,才是C#里把List转换成XML最务实的路径。
常见误区与注意事项
初学者常以为直接对List调用ToString就能得到XML,实际上那只是类型名而已。还有人用字符串相加拼XML,一旦内容含引号或尖括号就会导致解析失败。应当始终使用框架提供的序列化或DOM接口。
另外如果List元素来自ORM查询且是延迟加载集合,序列化时可能触发数据库连接已关闭的异常,建议先ToList加载到内存再转换。掌握这些细节,才能在工程中稳妥地完成C#中List到XML的转换任务。