本文針對 C# System.Xml.Serialization.XmlSerializer 進行系統講解,涵蓋基本用法、特性控制序列化行為、異常處理模式、大對象圖優化,並提供可直接運行的控制台示例。注意:此為 C# 技術內容,非 PHP。
System.Xml.Serialization.XmlSerializer:核心序列化器System.Xml.Serialization.* 特性:XmlRoot、XmlElement、XmlAttribute、XmlIgnore、XmlArray、XmlArrayItem 等System.IO.StringReader/Writer、MemoryStream、XmlTextWriter:流操作using System;
using System.Collections.Generic;
using System.Xml.Serialization;
public class Member
{
[XmlElement("Member_Num")] // 控制元素名
public string Num { get; set; }
public string Name { get; set; }
}
[XmlRoot("Our_Team")] // 控制根元素名
public class Team
{
[XmlIgnore] // 忽略此屬性,不序列化
public string InternalCode { get; set; }
[XmlAttribute("team_name")] // 序列化為屬性而非元素
public string Name { get; set; }
[XmlArray("Members")]
[XmlArrayItem("Member")]
public List<Member> Members { get; set; } = new();
}
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
public static class XmlHelper
{
/// <summary>
/// 對象序列化為 XML 字符串(UTF-8 無 BOM,縮進格式化)
/// </summary>
public static string Serialize<T>(T obj, string rootName = null) where T : class
{
if (obj == null) return string.Empty;
var serializer = new XmlSerializer(typeof(T), rootName != null ? new XmlRootAttribute(rootName) : null);
var settings = new XmlWriterSettings
{
Encoding = new UTF8Encoding(false), // 無 BOM
Indent = true,
IndentChars = " ",
OmitXmlDeclaration = false
};
using var ms = new MemoryStream();
using (var writer = XmlWriter.Create(ms, settings))
{
serializer.Serialize(writer, obj);
}
return Encoding.UTF8.GetString(ms.ToArray());
}
/// <summary>
/// XML 字符串反序列化為對象
/// </summary>
public static T Deserialize<T>(string xml) where T : class
{
if (string.IsNullOrWhiteSpace(xml)) return null;
var serializer = new XmlSerializer(typeof(T));
using var reader = new StringReader(xml);
return (T)serializer.Deserialize(reader);
}
/// <summary>
/// 文件級序列化/反序列化
/// </summary>
public static void SerializeToFile<T>(T obj, string filePath) where T : class
{
var xml = Serialize(obj);
File.WriteAllText(filePath, xml, new UTF8Encoding(false));
}
public static T DeserializeFromFile<T>(string filePath) where T : class
{
var xml = File.ReadAllText(filePath, Encoding.UTF8);
return Deserialize<T>(xml);
}
}
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
// 構建對象圖
var team = new Team
{
Name = "Development",
InternalCode = "DEV-001", // 將被忽略
Members = new List<Member>
{
new Member { Num = "001", Name = "Marry" },
new Member { Num = "002", Name = "John" }
}
};
// 序列化
string xml = XmlHelper.Serialize(team);
Console.WriteLine("=== 序列化結果 ===");
Console.WriteLine(xml);
/*
輸出:
<?xml version="1.0" encoding="utf-8"?>
<Our_Team team_name="Development">
<Members>
<Member>
<Member_Num>001</Member_Num>
<Name>Marry</Name>
</Member>
<Member>
<Member_Num>002</Member_Num>
<Name>John</Name>
</Member>
</Members>
</Our_Team>
*/
// 反序列化
var newTeam = XmlHelper.Deserialize<Team>(xml);
Console.WriteLine("\n=== 反序列化驗證 ===");
Console.WriteLine($"Team Name: {newTeam.Name}"); // Development
Console.WriteLine($"InternalCode: {newTeam.InternalCode}"); // null (被忽略)
foreach (var m in newTeam.Members)
{
Console.WriteLine($" {m.Num} - {m.Name}");
}
// 文件操作演示
XmlHelper.SerializeToFile(team, "team.xml");
var fromFile = XmlHelper.DeserializeFromFile<Team>("team.xml");
Console.WriteLine($"\n文件讀取: {fromFile.Name}");
}
}
| 特性 | 作用目標 | 效果 | 示例 |
|---|---|---|---|
XmlRoot | 類 | 根元素名、命名空間 | [XmlRoot("Data", Namespace="https://ns")] |
XmlElement | 屬性/字段 | 子元素名、類型、順序、命名空間 | [XmlElement("Item", Order=1)] |
XmlAttribute | 屬性/字段 | 序列化為 XML 屬性 | [XmlAttribute("id")] |
XmlIgnore | 屬性/字段 | 完全跳過 | [XmlIgnore] public string Pwd; |
XmlArray | 集合屬性 | 父數組元素名 | [XmlArray("Users")] |
XmlArrayItem | 集合屬性 | 子元素名、類型 | [XmlArrayItem("User", Type=typeof(User))] |
XmlText | 單一屬性 | 作為元素文本內容 | [XmlText] public string Content; |
XmlEnum | 枚舉字段 | 自定義枚舉值的 XML 表示 | [XmlEnum("ACTIVE")] Active = 1 |
XmlInclude | 類 | 包含衍生類型(多態序列化) | [XmlInclude(typeof(Derived))] |
[XmlInclude(typeof(Car))]
[XmlInclude(typeof(Bike))]
public abstract class Vehicle { public string Brand; }
public class Car : Vehicle { public int Doors; }
public class Bike : Vehicle { public bool HasBasket; }
// 序列化 List<Vehicle> 時能正確識別 Car/Bike 類型
var vehicles = new List<Vehicle> { new Car { Brand="Toyota", Doors=4 }, new Bike { Brand="Giant", HasBasket=true } };
public class CustomData : IXmlSerializable
{
public Dictionary<string, string> Data { get; set; }
public System.Xml.Schema.XmlSchema GetSchema() => null;
public void ReadXml(XmlReader reader)
{
reader.ReadStartElement();
while (reader.NodeType != XmlNodeType.EndElement)
{
var key = reader.Name;
reader.ReadStartElement();
var value = reader.ReadContentAsString();
Data[key] = value;
reader.ReadEndElement();
}
reader.ReadEndElement();
}
public void WriteXml(XmlWriter writer)
{
foreach (var kv in Data)
{
writer.WriteElementString(kv.Key, kv.Value);
}
}
}
XmlSerializer 構造函數會動態生成程序集,**必須緩存實例**,否則嚴重洩漏內存:
// 靜態緩存字典
private static readonly Dictionary<Type, XmlSerializer> _cache = new();
public static XmlSerializer GetSerializer(Type type)
{
lock (_cache)
{
if (!_cache.TryGetValue(type, out var serializer))
{
serializer = new XmlSerializer(type);
_cache[type] = serializer;
}
return serializer;
}
}
try
{
var obj = XmlHelper.Deserialize<Team>(xml);
}
catch (InvalidOperationException ex) when (ex.InnerException is XmlException xmlEx)
{
// XML 格式錯誤:xmlEx.LineNumber, xmlEx.LinePosition
logger.LogError(xmlEx, "XML 解析失敗");
throw new BusinessException("數據格式錯誤", ex);
}
catch (Exception ex)
{
logger.LogError(ex, "反序列化異常");
throw;
}
C# XmlSerializer 是功能強大、標準化的 XML 處理工具。掌握特性控制、序列化器緩存、異常處理、多態支持,即可應對企業級 XML 集成場景。現代 .NET 也可考慮 System.Text.Json (JSON) 或 YamlDotNet (YAML) 作為替代格式。