Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 由于格式化,XML反序列化在十进制解析时崩溃_C#_.net_Xml_Serialization_Xml Deserialization - Fatal编程技术网

C# 由于格式化,XML反序列化在十进制解析时崩溃

C# 由于格式化,XML反序列化在十进制解析时崩溃,c#,.net,xml,serialization,xml-deserialization,C#,.net,Xml,Serialization,Xml Deserialization,当我尝试将XML解析为对象时,会引发System.FormatException。据我所知,这是由于System.Xml.Serialization.XmlSerializer.Deserialize中使用的区域性造成的,它需要一个点作为十进制字符,但Xml包含一个逗号 对象如下所示: 公开密封类事务 { [XmlElement(“交易日期”)] 公共日期时间事务日期{get;set;} [XmlElement(“TransactionMount”)] 公共十进制数{get;set;} [Xm

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

对象如下所示:


公开密封类事务
{
[XmlElement(“交易日期”)]
公共日期时间事务日期{get;set;}
[XmlElement(“TransactionMount”)]
公共十进制数{get;set;}
[XmlElement(“transactionDescription”)]
公共字符串说明{get;set;}
[XmlElement(“transactionType”)]
公共int类型{get;set;}
来自xmlString(string xmlString)的公共静态事务
{
var reader=新的StringReader(xmlString);
var serializer=新的XmlSerializer(typeof(Transaction));
var实例=(事务)序列化程序。反序列化(读取器);
返回实例;
}
}
xml:

这暴露了一个我不想要的额外属性


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

XML序列化程序使用标准的数字和日期时间格式,该标准在W3C模式数据类型规范中定义


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

如果您知道生成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;
    }

相反,您可以使用一个属性来对
十进制数进行序列化/反序列化

见:

通过这种方式,您可以获取/设置
金额
,而无需担心它是如何序列化的。因为这是一个DTO,所以您可以创建另一个类,而不需要将
AmountSerialized
作为域对象(并使用类似的方法使转换变得轻松)

用法:

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));
}
var data=@”
2013-07-02
-459,00
描述
1.
";
var serializer=新的XmlSerializer(typeof(Transaction));
使用(变量流=新的StringReader(数据))
使用(var reader=XmlReader.Create(stream))
{
Write(序列化程序.反序列化(读取器));
}

另外,
transactionDate

的结束标记中有一个输入错误,这听起来像是XmlSerializer正在使用,并且应该相对独立于区域性,以避免跨机器/区域性的序列化/反序列化问题。我想你现在所做的可能是最好的方式(也许用
[XmlIgnore]
来装饰
AmountAsDecimal
,这样就更明显了)。不管怎样,只要序列化对象是纯数据传输对象,并且是从应用程序/业务逻辑中抽象出来的,那么我希望它不会对您造成太大的伤害。但是在第二次读取时,您可能需要翻转哪个属性被解析,哪个属性被序列化。公开
public decimal Amount
作为通常在代码API中获得/设置的值,但将其作为
[XmlIgnore]
使用。然后拥有一个
公共字符串SerializedAmount
属性,其get/set实现将格式化/解析您的专用区域性。至少这样,您用来编写
事务
对象的API不必考虑如何格式化字符串;它只写一个
十进制
值。如果您编写它的方式(例如更改
SerializedAmount
属性),那么您的代码并不在意。即使如此,从我的查询返回的XML包含带逗号的双精度。@SoftUx,我认为您找到了一个可能的解决方案。+1@在“您创建此XML”或“您针对第三方服务执行的查询”中使用Softux“我的查询”?如果是前者,我强烈建议对数字/日期时间值使用正确的XML格式。从长远来看会容易得多。是的,它来自第三方,我不打算再次序列化它。我的问题是在实现序列化之前创建的XML。(是的,在文本级别为XMLIO编写了大量代码)。为了保持这种兼容性,我将所有数据序列化为字符串,并自行处理格式问题。丑陋和笨拙,但它的工作。我用一个桥接应用程序内部状态和通过XML IO获得的状态的桥接类封装了格式化问题。我发现最佳实践是在一次尝试(或使用)中使用最少的代码。因为保存区域性不一定要在线程中,所以在手动保存线程的区域性是合适的
    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;
    }
[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;
    }
}
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));
}