如何在C#中将数组/类序列化为XML元素的属性?
如何将数组/结构体序列化为XML元素的属性而非子元素
结构体场景:用类型转换器实现
以Margin结构体为例,要把它序列化为XML元素的属性(如Margin="0,0,0,0"),可以通过类型转换器配合XmlAttribute特性实现:
步骤1:定义结构体并实现字符串转换逻辑
public struct Margin { public int Left { get; set; } public int Top { get; set; } public int Right { get; set; } public int Bottom { get; set; } public Margin(int left, int top, int right, int bottom) { Left = left; Top = top; Right = right; Bottom = bottom; } // 从逗号分隔字符串解析为Margin public static Margin Parse(string value) { var parts = value.Split(','); if (parts.Length != 4) throw new FormatException("格式必须为 left,top,right,bottom"); return new Margin( int.Parse(parts[0].Trim()), int.Parse(parts[1].Trim()), int.Parse(parts[2].Trim()), int.Parse(parts[3].Trim()) ); } // 将Margin转为逗号分隔字符串 public override string ToString() { return $"{Left},{Top},{Right},{Bottom}"; } }
步骤2:创建类型转换器
让XML序列化器能识别结构体与字符串的转换规则:
public class MarginConverter : TypeConverter { public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); } public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { if (value is string str) return Margin.Parse(str); return base.ConvertFrom(context, culture, value); } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if (destinationType == typeof(string) && value is Margin margin) return margin.ToString(); return base.ConvertTo(context, culture, value, destinationType); } }
步骤3:标记结构体并配置XML属性
给结构体添加类型转换器特性,然后在目标类中把Margin属性标记为XML属性:
[TypeConverter(typeof(MarginConverter))] public struct Margin { /* 原有代码 */ } public class SomeElement { [XmlAttribute] public Margin Margin { get; set; } }
测试序列化
运行以下代码即可得到目标格式:
var element = new SomeElement { Margin = new Margin(0, 0, 0, 0) }; var serializer = new XmlSerializer(typeof(SomeElement)); using var writer = new StringWriter(); serializer.Serialize(writer, element); Console.WriteLine(writer.ToString());
输出结果:
<?xml version="1.0" encoding="utf-16"?> <SomeElement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Margin="0,0,0,0" />
数组场景:用代理属性实现
如果要序列化数组(如int[])为XML属性,可以通过代理字符串属性中转:
public class SomeElement { private int[] _sizes; // 用于XML序列化的代理属性(作为XML属性) [XmlAttribute("Sizes")] public string SizesString { get => _sizes != null ? string.Join(",", _sizes) : null; set => _sizes = value?.Split(',').Select(s => int.Parse(s.Trim())).ToArray(); } // 实际业务中使用的数组属性(忽略XML序列化) [XmlIgnore] public int[] Sizes { get => _sizes; set => _sizes = value; } }
序列化后会生成:<SomeElement Sizes="1,2,3,4" />,反序列化时会自动将字符串转回数组。
备选方案:自定义IXmlSerializable
如果需要更复杂的控制逻辑,可以实现IXmlSerializable接口手动处理序列化过程:
public class SomeElement : IXmlSerializable { public Margin Margin { get; set; } public XmlSchema GetSchema() => null; public void ReadXml(XmlReader reader) { var marginStr = reader.GetAttribute("Margin"); if (!string.IsNullOrEmpty(marginStr)) Margin = Margin.Parse(marginStr); } public void WriteXml(XmlWriter writer) { writer.WriteAttributeString("Margin", Margin.ToString()); } }
这种方式灵活性更高,但需要自己处理所有XML读写逻辑,适合复杂场景。
内容的提问来源于stack exchange,提问作者Cobret
相关产品推荐
相关产品推荐

