c# - 反序列化报错:Input string was not in a correct format

来源:互联网 发布:淘宝买的袖剑能杀人吗 编辑:程序博客网 时间:2024/05/18 00:12

1. 问题:

一直没有仔细考虑过反序列化Nullable字段的问题,貌似也没发现过问题,因为序列化及反序列化如果由同一个人或Team写的话,会掩盖这个问题。

请大家看一下代码:

public class A{    public String Name { get; set; }    public decimal? Value {get; set;}    public bool ShouldSerializeValue()    {        return this.Value.HasValue;    }}class Program  {      static void Main(string[] args)      {            string xmlContent =   @"<A>      <Name>aa</Name>      <Value/>  </A>";          // DeserializeXML方法请参照: http://blog.csdn.net/yuxuac/article/details/16830589          A a2 = Serializer.DeserializeXML<A>(xmlContent);             Console.ReadLine();      }  } 

大家觉得代码能正确执行么? 

答案是不能,错误信息为:Input string was not in a correct format。


2. 原因分析:

原因是什么?

让我们先从ShouldSerialize()方法讲起, 此方法的作用从其方法签名可见一二, 使用此方法可以控制是否序列化某些字段(当然,通常情况下用来会控制Nullable类型的字段在什么情况下被序列化)。

请看以下示例:

1. 如果直接序列化一个A对象,故意不给Value赋值。

A a = new A(){ Name = "aa"};string str = Util.SerializeXML(a);

XML会长这个样子,我们定义了方法ShouldSerializeValue(),其定义中明确描述了,只有Value有值的情况下才序列化,因此Value节点没有被序列化:

<?xml version="1.0" encoding="utf-16"?><A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">  <Name>aa</Name></A>

2. 如果我们去掉A中的ShouldSerializeValue() 方法:

public class A  {      public String Name { get; set; }      public decimal? Value {get; set;}  }A a = new A(){ Name = "aa"};  string str = Serializer.SerializeXML(a)

XML会长这个样子,Value节点还存在(包含属性:xsi:nil="true"),这是我们不定义ShouldSerialize方法的时候的默认情况。

<?xml version="1.0" encoding="utf-16"?><A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">  <Name>aa</Name>  <Value xsi:nil="true" /></A>

因此,ShouldSerializeXX()的作用,即在序列化时,控制是否序列化指定字段。它的用法是ShouldSerializeXX(),此处的XX即你定义的字段名称。


再看我们上面的代码,有ShouldSerializeValue()方法,反序列化的时候,是否此方法还起作用呢?(此时我们的XML中有一个<Value/>节点,没有值。)我曾想当然的以为它在反序列化的时候也会work。

但答案是不行,而且还报错。原因是什么?


原因是:在反序列化的时候,请注意我们的xmlContent变量定义的XML内容,<Value/>节点存在;事实上反序列化无法识别没有被标记为xsi:nil="true"的可空对象,它会认为这是个非法的值。

或许将来会加上ShouldDeserializeXX()方法来解决这个问题。


3. 解决办法:

原因找到了,怎么解决?有两个方法:

1. 去掉Value节点。

2. 人为控制反序列化的过程(就是修改Value字段的定义,控制字符串怎么赋值给Nullable的对象,Nullable对象怎么赋值到字符串),修正代码如下:

    public class A    {        public String Name { get; set; }        public bool ShouldSerializeValue()        {            return this.Value.HasValue;        }        [XmlIgnore]        public decimal? Value { get; set; }        [XmlElement(ElementName = "Value")]        public string ValueStr        {            get            {                if (this.Value.HasValue)                    return this.Value.Value.ToString("f");                else                    return string.Empty;            }            set            {                if (string.IsNullOrEmpty(value))                    this.Value = null;                else                    this.Value = decimal.Parse(value);            }        }    }

此时我们在执行上文提到的Main方法,发现不会报错了,而且Value的值被很好地处理了。

0 0
原创粉丝点击