由于格式设置,XML反序列化在十进制分析时崩溃

本文关键字:十进制 反序列化 崩溃 XML 于格式 格式 设置 | 更新日期: 2023-09-27 18:20:44

当我试图将XML解析为对象时,会引发System.FormatException。据我所知,这是由于System.Xml.Serialization.XmlSerializer.Deserialize中使用的区域性,它需要一个点作为十进制字符,但Xml包含一个逗号。

对象看起来如下:


public sealed class Transaction
{
    [XmlElement("transactionDate")]
    public DateTime TransactionDate { get; set; }
    [XmlElement("transactionAmount")]
    public decimal Amount { get; set; }
    [XmlElement("transactionDescription")]
    public string Description { get; set; }
    [XmlElement("transactionType")]
    public int Type { get; set; }
    public static Transaction FromXmlString(string xmlString)
    {
        var reader = new StringReader(xmlString);
        var serializer = new XmlSerializer(typeof(Transaction));
        var instance = (Transaction) serializer.Deserialize(reader);
        return instance;
    }
}

xml:


<transaction>
    <transactionDate> 2013-07-02 <transactionDate>
    <transactionAmount>-459,00</transactionAmount>
    <transactionDescription>description</transactionDescription>
    <transactionType>1</transactionType>
</transaction>

我通过引入第二个属性来实现这一点,该属性使用我自己的文化来解析第一个属性:


namespace MyNamespace
{
    [XmlRoot("transaction"), XmlType("Transaction")]
    public sealed class Transaction
    {
        [XmlElement("transactionDate")]
        public DateTime TransactionDate { get; set; }
        [XmlElement("transactionAmount")]
        public string Amount { get; set; }
        public decimal AmountAsDecimal {
            get
            {
                decimal value;
                Decimal.TryParse(Amount, NumberStyles.Any, CultureInfo.CreateSpecificCulture("sv-SE"), out value);
                return value;
            }
        }
        [XmlElement("transactionDescription")]
        public string Description { get; set; }
        [XmlElement("transactionType")]
        public int Type { get; set; }
        public static Transaction FromXmlString(string xmlString)
        {
            var reader = new StringReader(xmlString);
            var serializer = new XmlSerializer(typeof(Transaction));
            var instance = (Transaction) serializer.Deserialize(reader);
            return instance;
        }
    }
}

这暴露了一个我不想在那里的额外财产。

所以我的问题是:有没有其他方法可以做到这一点,而不必迭代每个元素并"手动"解析/分配给对象?

由于格式设置,XML反序列化在十进制分析时崩溃

XML序列化程序使用标准化的Number和DateTime格式,该标准在W3C模式数据类型规范中定义http://www.w3.org/TR/xmlschema-2/.

不要期望XmlSerializer关注线程的CultureInfo,它有意使用标准化的格式来确保您可以独立于区域性/区域设置进行序列化/反序列化。

您可以使用一个属性来序列化/反序列化decimal

请参阅:将XML部分反序列化为对象

[XmlType("transaction")]
public sealed class Transaction
{
    [XmlElement("transactionDate")]
    public DateTime TransactionDate { get; set; }
    [XmlIgnore]
    public decimal Amount { get; set; }
    [XmlElement("transactionAmount")]
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
    public string AmountSerialized
    {
        get
        {
            return Amount.ToString(CultureInfo.CreateSpecificCulture("sv-SE"));
        }
        set
        {
            decimal amount;
            Decimal.TryParse(value, NumberStyles.Any, CultureInfo.CreateSpecificCulture("sv-SE"), out amount);
            Amount = amount;
        }
    }
    [XmlElement("transactionDescription")]
    public string Description { get; set; }
    [XmlElement("transactionType")]
    public int Type { get; set; }
    public static Transaction FromXmlString(string xmlString)
    {
        var reader = new StringReader(xmlString);
        var serializer = new XmlSerializer(typeof(Transaction));
        var instance = (Transaction) serializer.Deserialize(reader);
        return instance;
    }
}

通过这种方式,您可以获得/设置Amount,而无需担心它是如何序列化的。由于这是一个DTO,您可以在不使用AmountSerialized作为域对象的情况下创建另一个类(并使用类似AutoMapper的东西来简化转换)。

用法:

var data = @"<transaction>
                <transactionDate>2013-07-02</transactionDate>
                <transactionAmount>-459,00</transactionAmount>
                <transactionDescription>description</transactionDescription>
                <transactionType>1</transactionType>
            </transaction>";
var serializer = new XmlSerializer(typeof(Transaction));
using(var stream = new StringReader(data))
using(var reader = XmlReader.Create(stream))
{
     Console.Write(serializer.Deserialize(reader));
}

此外,transactionDate的结束标签中也有一个拼写错误。

如果您知道生成XML的区域性,一个简单的解决方案是在反序列化之前将当前线程的区域性切换到该区域性。

    System.Globalization.CultureInfo oCurrentCulture = null;
    try
    {
        // Save the current culture
        oCurrentCulture = System.Threading.Thread.CurrentThread.CurrentCulture;
        System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("de-DE");
        // Do your work
    }
    finally
    {
                    // Restore the saved culture
        System.Threading.Thread.CurrentThread.CurrentCulture = oCurrentCulture;
    }