我有一个自定义异常:
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;
}
答案 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。