XML反序列化后如何将数字格式化为带千分位的字符串?
解决XML反序列化后Value字段千分位格式化问题
问题描述
现有如下XML数据:
"<ArrayOfClsLog xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"> <ClsLog> <Subject>sth</Subject> <Value>123456</Value> <Comment>val</Comment> </ClsLog> </ArrayOfClsLog>"
使用以下代码进行反序列化:
var tmpSerializer = new XmlSerializer(typeof(ObservableCollection<ClsLog>)); tmpResult = tmpSerializer.Deserialize(tmpReader) as ObservableCollection<ClsLog>;
初始的ClsLog类定义:
public class ClsLog { public string Subject { get; set; } public string Value { get; set; } public string Comment { get; set; } }
反序列化流程正常,但需要将Value字段的数字(如123456)转换为带千分位的格式(如123,456)。尝试修改ClsLog类后无效果,用LINQ修改集合时出现异常。
错误分析
修改
ClsLog属性的问题:
修改后的Value属性getter中,decimal.Parse(Value.ToString())会递归调用自身的getter方法,导致栈溢出;同时setter为空,反序列化时无法将XML中的值存入属性,因此永远无法得到正确的原始值进行格式化。LINQ遍历的问题:
List.ForEach()是无返回值的方法,不能直接赋值给tmpResult;同时如果Value属性的setter存在问题,即使遍历也无法修改值。
正确解决方案
方案一:使用内部字段存储原始值,对外返回格式化结果
修改ClsLog类,用私有字段存储原始值,通过XML特性控制序列化映射,对外提供格式化后的Value:
public class ClsLog { public string Subject { get; set; } // 映射XML中的<Value>元素,存储原始未格式化的值 [XmlElement("Value")] private string _rawValue; // 对外提供格式化后的Value,不参与XML序列化 [XmlIgnore] public string Value { get { // 安全解析,避免格式错误导致异常 if (decimal.TryParse(_rawValue, out decimal numericValue)) { return numericValue.ToString("N2", System.Globalization.CultureInfo.InvariantCulture); } // 解析失败时返回原始值 return _rawValue ?? string.Empty; } set { _rawValue = value; } } public string Comment { get; set; } }
此方案中,反序列化时XML的Value值会存入_rawValue,访问Value属性时自动返回格式化后的字符串。
方案二:反序列化后遍历集合手动格式化
保持原始ClsLog类不变,反序列化完成后遍历集合,逐个格式化Value字段:
// 反序列化代码不变 var tmpSerializer = new XmlSerializer(typeof(ObservableCollection<ClsLog>)); tmpResult = tmpSerializer.Deserialize(tmpReader) as ObservableCollection<ClsLog>; // 遍历集合格式化每个元素的Value foreach (var logEntry in tmpResult) { if (decimal.TryParse(logEntry.Value, out decimal numericValue)) { logEntry.Value = numericValue.ToString("N2", System.Globalization.CultureInfo.InvariantCulture); } }
如果习惯使用LINQ,可以用Select转换后重新生成ObservableCollection:
tmpResult = new ObservableCollection<ClsLog>( tmpResult.Select(logEntry => { if (decimal.TryParse(logEntry.Value, out decimal numericValue)) { logEntry.Value = numericValue.ToString("N2", System.Globalization.CultureInfo.InvariantCulture); } return logEntry; }) );
内容的提问来源于stack exchange,提问作者maryam mohammadbagheri
相关产品推荐
相关产品推荐

