DataContractJsonSerializer反序列化List <t>抛出错误

时间:2016-10-14 16:40:23

标签: c# serialization deserialization datacontractserializer datacontractjsonserializer

我有一个自定义异常:

apt-get install imagemagick

每当它尝试反序列化时,该行抛出“对象必须实现IConvertible”异常:[Serializable] public class MyCustomException : Exception { public List<ErrorInfo> ErrorInfoList { get; set; } protected MyCustomException (SerializationInfo info, StreamingContext context) : base(info, context) { this.ErrorInfoList = (List<ErrorInfo>)info.GetValue("ErrorInfoList", typeof(List<ErrorInfo>)); } [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)] public override void GetObjectData(SerializationInfo info, StreamingContext context) { if (info == null) { throw new ArgumentNullException("info"); } info.AddValue("ErrorInfoList ", this.ErrorInfoList, typeof(List<ErrorInfo>)); base.GetObjectData(info, context); } }

以下是进行序列化的代码:

(List<ErrorInfo>)info.GetValue("ErrorInfoList", typeof(List<ErrorInfo>))

以下是进行反序列化的代码:

using(MemoryStream memStm = new MemoryStream())
{
    XmlObjectSerializer ser = new DataContractJsonSerializer(
        typeof(MyCustomException),
        new Type[] {
            typeof(List<ErrorInfo>),
            typeof(ErrorInfo)
        }
    );

    ser.WriteObject(memStm, (MyCustomException)context.Exception);
    memStm.Seek(0, SeekOrigin.Begin);
    using (StreamReader streamReader = new StreamReader(memStm))
    {
        response.Content = new StringContent(streamReader.ReadToEnd());
    }
}

这是ErrorInfo类的代码:

using(MemoryStream memStm = new MemoryStream(response.Content.ReadAsByteArrayAsync().Result))
{
    DataContractJsonSerializer deserializer = new DataContractJsonSerializer(
        typeof(MyCustomException),
        new Type[] {
            typeof(List<ErrorInfo>),
            typeof(ErrorInfo)
        }
    );
    UserPortalException upEx = (UserPortalException)deserializer.ReadObject(memStm);
    throw upEx;
}

2 个答案:

答案 0 :(得分:1)

这里的基本问题是ISerializable接口最初设计(在.Net 1中)与BinaryFormatter一起使用。并且,虽然BinaryFormatter序列化流包含完整的类型信息,但JSON是弱类型的。这会导致Stand-Alone JSON Serialization

中描述的问题
  

支持和不支持的可ISerializable类型

     

通常,在序列化/反序列化JSON时,完全支持实现ISerializable接口的类型。但是,其中一些类型(包括某些.NET Framework类型)的实现方式使得特定于JSON的序列化方面导致它们不能正确反序列化:

     
      
  • 使用ISerializable,预先不知道单个数据成员的类型。这导致类似于将类型反序列化为对象的多态情况。如前所述,这可能会导致JSON中丢失类型信息。例如,在其ISerializable实现中序列化枚举并尝试直接反序列化为枚举(没有适当的强制转换)的类型失败,因为枚举是使用JSON中的数字序列化的,而JSON数字反序列化为内置.NET数值类型(Int32,十进制或双精度)。因此,曾经是枚举值的数字将会丢失。
  •   

您遇到的只是类型信息的丢失。如果查看为自定义异常生成的JSON,您将看到:

{"ErrorInfoList":[{"__type":"ErrorInfo:#Question40048102","Code":0}],"ClassName":"Question40048102.MyCustomException","Message":null,"Data":null,"InnerException":null,"HelpURL":null,"StackTraceString":null,"RemoteStackTraceString":null,"RemoteStackIndex":0,"ExceptionMethod":null,"HResult":-2146233088,"Source":null}

每个"__type"都有一个ErrorInfo类型提示,但ErrorInfoList没有类型提示,因为DataContractJsonSerializer does not support type hints for collections。因此,ErrorInfoList被反序列化为包含object []个对象而不是ErrorInfo的{​​{1}}数组,从而导致您看到错误。

因此,原则上,您可以按如下方式更改List<ErrorInfo>的初始化:

ErrorInfoList

但是,这会破坏二进制和XML数据协定反序列化,其中条目值已经正确输入。它也会中断使用完全不同的机制的Json.NET deserialization,即在this.ErrorInfoList = ((IEnumerable<object>)info.GetValue("ErrorInfoList", typeof(object []))).Cast<ErrorInfo>().ToList(); 中存储JToken值并使用自定义IFormatterConverter按需反序列化。

因此,需要一点代码气味来支持所有上述序列化程序:

SerializationInfo

答案 1 :(得分:0)

尝试在IConvertible课程上实施ErrorInfo

我的猜测是,它无法从“永远不会发生的事情”中解脱出来。在值中被命名为&#39; ErrorInfoList&#39;在SerializationInfo上下文中的List。所以我在ErrorInfo上实现了IConvertible。