You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 12:45:38