JSON.NET: 如何反序列化特定的异常类型
JSON.NET: How deserialize specific Exception type
考虑以下非常简单的代码。
var ex_to_serialize = new Exception("something wrong", new NullReferenceException("set to null"));
var serialized_ex = JsonConvert.SerializeObject(ex_to_serialize);
var deserialized_ex = JsonConvert.DeserializeObject<Exception>(serialized_ex);
Console.WriteLine($"Type of inner exception: {deserialized_ex.InnerException.GetType().Name}");
瞧瞧...内部异常类型是 Exception
而不是 NullReferenceException
。
所以我搜索了 SO 并找到了很多用于反序列化的自定义 JsonConverter
的示例(因为序列化的 JSON 包含 ClassName
属性,可用于创建特定类型) .所以我写了一个(为了简单起见,只有 ReadJson
,其余照常)。
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var json_object = Newtonsoft.Json.Linq.JObject.Load(reader);
var target_type_name = json_object.Value<string>("ClassName");
var target_type = Type.GetType(target_type_name);
var target = Activator.CreateInstance(target_type);
serializer.Populate(json_object.CreateReader(), target);
return target;
}
并在调用上面的DeserializeObject
函数时传递这个转换器。
这次,我得到异常:
Newtonsoft.Json.JsonSerializationException: Cannot populate JSON object onto type 'System.Exception'. Path 'ClassName'
就我深入研究 Newtonsoft.Json 代码而言,“问题”似乎是 Exception
是 [Serializable]
和 ISerializable
所以它使用了 SerializableContract不支持填充对象。但在这里我绝望了:-(。有人可以帮助我吗?
(上面的例子只是为了简单起见,我需要序列化和反序列化我自己的异常,这要复杂得多。Newtonsoft.Json使用了11.0.0.2版本。)
您忘记了 TypeNameHandling 设置。[Typehandling]
所以请像下面这样修复你的代码,它将正常工作
var ex_to_serialize = new Exception("something wrong", new NullReferenceException("set to null"));
var serialized_ex = JsonConvert.SerializeObject(ex_to_serialize,new JsonSerializerSettings{TypeNameHandling = TypeNameHandling.All});
var deserialized_ex = JsonConvert.DeserializeObject<Exception>(serialized_ex, new JsonSerializerSettings{TypeNameHandling = TypeNameHandling.All});
Console.WriteLine($"Type of inner exception: {deserialized_ex.InnerException.GetType().Name}");
考虑以下非常简单的代码。
var ex_to_serialize = new Exception("something wrong", new NullReferenceException("set to null"));
var serialized_ex = JsonConvert.SerializeObject(ex_to_serialize);
var deserialized_ex = JsonConvert.DeserializeObject<Exception>(serialized_ex);
Console.WriteLine($"Type of inner exception: {deserialized_ex.InnerException.GetType().Name}");
瞧瞧...内部异常类型是 Exception
而不是 NullReferenceException
。
所以我搜索了 SO 并找到了很多用于反序列化的自定义 JsonConverter
的示例(因为序列化的 JSON 包含 ClassName
属性,可用于创建特定类型) .所以我写了一个(为了简单起见,只有 ReadJson
,其余照常)。
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var json_object = Newtonsoft.Json.Linq.JObject.Load(reader);
var target_type_name = json_object.Value<string>("ClassName");
var target_type = Type.GetType(target_type_name);
var target = Activator.CreateInstance(target_type);
serializer.Populate(json_object.CreateReader(), target);
return target;
}
并在调用上面的DeserializeObject
函数时传递这个转换器。
这次,我得到异常:
Newtonsoft.Json.JsonSerializationException: Cannot populate JSON object onto type 'System.Exception'. Path 'ClassName'
就我深入研究 Newtonsoft.Json 代码而言,“问题”似乎是 Exception
是 [Serializable]
和 ISerializable
所以它使用了 SerializableContract不支持填充对象。但在这里我绝望了:-(。有人可以帮助我吗?
(上面的例子只是为了简单起见,我需要序列化和反序列化我自己的异常,这要复杂得多。Newtonsoft.Json使用了11.0.0.2版本。)
您忘记了 TypeNameHandling 设置。[Typehandling] 所以请像下面这样修复你的代码,它将正常工作
var ex_to_serialize = new Exception("something wrong", new NullReferenceException("set to null"));
var serialized_ex = JsonConvert.SerializeObject(ex_to_serialize,new JsonSerializerSettings{TypeNameHandling = TypeNameHandling.All});
var deserialized_ex = JsonConvert.DeserializeObject<Exception>(serialized_ex, new JsonSerializerSettings{TypeNameHandling = TypeNameHandling.All});
Console.WriteLine($"Type of inner exception: {deserialized_ex.InnerException.GetType().Name}");