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

如何让C#类兼容多xsi:type的同名XML标签反序列化

处理XML反序列化中带不同xsi:type的同名标签问题

你遇到的这个情况很典型——同一个XML标签但通过xsi:type区分不同的数据类型,要让C#的XmlSerializer正确识别并反序列化,咱们可以通过基类+派生类+XmlInclude特性的组合来搞定,具体步骤如下:

第一步:定义对应不同xsi:type的派生类

首先,给两种field-value类型分别创建对应的类,同时定义一个基类作为它们的父类:

// 基类,不需要XmlType特性,具体类型由派生类指定
public abstract class FieldValueBase { }

// 对应xsi:type="field-text-valueType"的文本类型
[XmlType("field-text-valueType", Namespace = "http://www.crsoftwareinc.com/xml/ns/titanium/common/v1_0")]
public class TextFieldValue : FieldValueBase
{
    [XmlElement(ElementName = "value", Namespace = "http://www.crsoftwareinc.com/xml/ns/titanium/common/v1_0")]
    public string Value { get; set; }
}

// 对应xsi:type="field-date-valueType"的日期类型
[XmlType("field-date-valueType", Namespace = "http://www.crsoftwareinc.com/xml/ns/titanium/common/v1_0")]
public class DateFieldValue : FieldValueBase
{
    [XmlElement(ElementName = "value", Namespace = "http://www.crsoftwareinc.com/xml/ns/titanium/common/v1_0")]
    public DateTime Value { get; set; }
}

第二步:在父级模型中添加XmlInclude特性指定派生类型

接下来定义包含field标签的类,并且在最上层的根模型类上添加XmlInclude特性,告诉XmlSerializer要识别哪些派生类型:

// 定义<field>对应的类
[XmlType("field", Namespace = "http://www.crsoftwareinc.com/xml/ns/titanium/common/v1_0")]
public class Field
{
    [XmlAttribute("name")]
    public string Name { get; set; }

    // 用基类FieldValueBase作为属性类型,兼容两种派生类型
    [XmlElement(ElementName = "field-value", Namespace = "http://www.crsoftwareinc.com/xml/ns/titanium/common/v1_0")]
    public FieldValueBase FieldValue { get; set; }
}

// 最上层的<user-defined-data-row>类,必须添加XmlInclude声明派生类型
[XmlRoot(ElementName = "user-defined-data-row", Namespace = "http://www.crsoftwareinc.com/xml/ns/titanium/common/v1_0")]
[XmlInclude(typeof(TextFieldValue))]
[XmlInclude(typeof(DateFieldValue))]
public class UserDefinedDataRow
{
    [XmlElement(ElementName = "field", Namespace = "http://www.crsoftwareinc.com/xml/ns/titanium/common/v1_0")]
    public List<Field> Fields { get; set; }
}

第三步:执行反序列化操作

现在就可以正常反序列化你的XML了,注意XML里要包含xsi命名空间声明(比如xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"),XmlSerializer会自动根据xsi:type匹配对应的派生类:

string xmlContent = @"<user-defined-data-row xmlns=""http://www.crsoftwareinc.com/xml/ns/titanium/common/v1_0"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
    <field name=""entity"">
        <field-value xsi:type=""field-text-valueType"">
            <value>Test</value>
        </field-value>
    </field>
    <field name=""expiry_date"">
        <field-value xsi:type=""field-date-valueType"">
            <value>2001-10-07</value>
        </field-value>
    </field>
</user-defined-data-row>";

XmlSerializer serializer = new XmlSerializer(typeof(UserDefinedDataRow));
using (StringReader reader = new StringReader(xmlContent))
{
    UserDefinedDataRow result = (UserDefinedDataRow)serializer.Deserialize(reader);
    
    // 处理反序列化结果,通过类型判断区分不同字段类型
    foreach (var field in result.Fields)
    {
        if (field.FieldValue is TextFieldValue textField)
        {
            Console.WriteLine($"文本字段 {field.Name}: {textField.Value}");
        }
        else if (field.FieldValue is DateFieldValue dateField)
        {
            Console.WriteLine($"日期字段 {field.Name}: {dateField.Value:yyyy-MM-dd}");
        }
    }
}

关键注意事项

  • 所有类的Namespace必须和XML中的默认命名空间完全一致,否则序列化器会识别不到标签
  • XmlInclude特性必须加在直接参与反序列化的根类或父类上,确保序列化器能加载到所有派生类型
  • 反序列化后,可通过is关键字判断类型,进而处理对应的数据

内容的提问来源于stack exchange,提问作者OHMR

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:42:01