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

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 =   
@"  
    aa  
      
";  
        // DeserializeXML方法请参照: http://blog.csdn.net/yuxuac/article/details/16830589  
        A a2 = Serializer.DeserializeXML(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节点没有被序列化:



  aa

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方法的时候的默认情况。



  aa
  

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


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

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


原因是:在反序列化的时候,请注意我们的xmlContent变量定义的XML内容,节点存在;事实上反序列化无法识别没有被标记为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的值被很好地处理了。

你可能感兴趣的:(序列化)