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

.NET 8中XmlSerializer不序列化派生值问题排查

问题原因

XmlSerializer 默认只会序列化同时拥有公共 get 和 set 访问器的属性。你定义的 AmountAsString(表达式体属性,本质只读)和 AnotherTry(仅包含 get 方法)都是只读属性,不符合序列化要求,因此被忽略。即使去掉 ToString("c2"),只读属性的本质没变,结果依然不会被序列化。

解决方案

针对你的需求(将decimal序列化为保留两位小数的格式),提供以下几种可行方案:

方案1:给只读属性添加空setter

既然序列化器需要setter,我们可以给这两个属性添加一个空的公共setter,不需要任何逻辑:

[XmlRoot(Namespace = "urn:iso:std:iso:20022:tech:xsd:pain.008.001.08")]
public class DecimalTestCase
{
    [XmlElement("IAmDecimal")]
    public decimal Value { get; set; }

    [XmlElement("IAmString")]
    public string AmountAsString { get => Value.ToString("c2"); set { } }

    [XmlElement("IAmAlsoString")]
    public string AnotherTry
    {
        get => Value.ToString("c2");
        set { }
    }
}

这样序列化器就能识别并处理这两个属性了。

方案2:直接处理decimal值,序列化格式化后的结果

如果你不需要同时保留原decimal字段的序列化结果,可以直接将decimal值四舍五入到两位小数,或者格式化后序列化:

[XmlRoot(Namespace = "urn:iso:std:iso:20022:tech:xsd:pain.008.001.08")]
public class DecimalTestCase
{
    // 标记原字段不序列化
    [XmlIgnore]
    public decimal Value { get; set; }

    [XmlElement("FormattedAmount")]
    public string FormattedValue => Math.Round(Value, 2).ToString("F2"); 
    // 注:"F2"保留两位小数(无货币符号),"c2"会带货币符号,可按需选择
}

序列化后会得到<FormattedAmount>123.12</FormattedAmount>这样的结果。

方案3:实现IXmlSerializable自定义序列化逻辑

如果需要更灵活的控制,可以实现IXmlSerializable接口,完全自定义序列化过程:

[XmlRoot(Namespace = "urn:iso:std:iso:20022:tech:xsd:pain.008.001.08")]
public class DecimalTestCase : IXmlSerializable
{
    public decimal Value { get; set; }

    public XmlSchema GetSchema() => null;

    public void ReadXml(XmlReader reader)
    {
        // 按需实现反序列化逻辑
        reader.ReadStartElement();
        Value = decimal.Parse(reader.ReadElementContentAsString("IAmDecimal", ""));
        reader.ReadEndElement();
    }

    public void WriteXml(XmlWriter writer)
    {
        // 自定义输出XML结构
        writer.WriteElementString("IAmDecimal", Value.ToString());
        writer.WriteElementString("IAmString", Value.ToString("c2"));
        writer.WriteElementString("IAmAlsoString", Math.Round(Value, 2).ToString("F2"));
    }
}

这种方式完全由你控制输出的XML结构,适合复杂场景。

注意事项
  • 若不需要货币符号,避免使用"c2"格式符,改用"F2"确保输出纯数字格式。
  • 建议先用Math.Round(Value, 2)处理decimal值再格式化,避免ToString时的精度偏差问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.04 10:09:52