我有一个类,其类型为Object,可能包含一个TimeSpan对象。
我正在对此进行序列化并将其反序列化:
public class MyObject
{
public object myTimeSpan { get; set; }
}
...
var myObject = new MyObject { myTimeSpan = TimeSpan.FromDays(2) };
var json = JsonConvert.SerializeObject(myObject);
...
var duplicateObject = JsonConvert.DeserializeObject<MyObject>(json);
当我这样做时,plicateObject.myTimeSpan包含字符串“ 2:00:00”。
如何获取反序列化为TimeSpan对象的对象?
两点:
我不处理在其他地方已序列化的字符串。我要反序列化的唯一字符串是我序列化的字符串。
该字段必须是object类型的-它可能包含字符串或DateTime,或者可能包含TimeSpan。目前,这只是我遇到问题的TimeSpan。
最佳答案
Json.Net具有TypeNameHandling
设置,用于处理未知类型,以便可以正确地反序列化它们。启用此设置后,它将导致Json.Net将特殊的$type
属性插入JSON,然后在反序列化时将其用作提示。不幸的是,此设置似乎不适用于TimeSpan
之类的“简单”类型,因为它们的值被序列化为字符串而不是对象。
要变通解决此问题,我建议创建一个使用相同想法的自定义JsonConverter
。转换器将直接输出具有两个属性的子对象表示形式:type
和value
,而不是直接输出对象的字符串值。子对象的type
属性将包含该对象的程序集限定类型名称,而value
属性将包含实际的序列化值。反序列化时,转换器将查找type
属性,以从value属性中了解要实例化的对象类型。这种方法的好处是您不必向模型类添加任何其他属性或逻辑。
这是它在代码中的外观:
class UnknownObjectConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JObject jo = new JObject();
jo["type"] = value.GetType().AssemblyQualifiedName;
jo["value"] = JToken.FromObject(value, serializer);
jo.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
Type type = Type.GetType(jo["type"].ToString(), throwOnError: true);
return jo["value"].ToObject(type, serializer);
}
}
要使用转换器,只需使用
object
属性装饰类中需要特殊处理的所有[JsonConverter]
属性,如下所示:public class MyObject
{
[JsonConverter(typeof(UnknownObjectConverter))]
public object MyValue { get; set; }
}
这是一个往返演示,展示了如何针对几种不同的类型工作。
class Program
{
static void Main(string[] args)
{
List<MyObject> list = new List<MyObject>
{
new MyObject { MyValue = TimeSpan.FromDays(2) },
new MyObject { MyValue = "foo" },
new MyObject { MyValue = new DateTime(2014, 12, 20, 17, 06, 44) },
new MyObject { MyValue = new Tuple<int, bool>(23, true) }
};
string json = JsonConvert.SerializeObject(list, Formatting.Indented);
Console.WriteLine(json);
Console.WriteLine();
list = JsonConvert.DeserializeObject<List<MyObject>>(json);
foreach (MyObject obj in list)
{
Console.WriteLine(obj.MyValue.GetType().Name + ": " + obj.MyValue.ToString());
}
}
}
这是输出:
[
{
"MyValue": {
"type": "System.TimeSpan, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"value": "2.00:00:00"
}
},
{
"MyValue": {
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"value": "foo"
}
},
{
"MyValue": {
"type": "System.DateTime, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"value": "2014-12-20T17:06:44"
}
},
{
"MyValue": {
"type": "System.Tuple`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"value": {
"Item1": 23,
"Item2": true
}
}
}
]
TimeSpan: 2.00:00:00
String: foo
DateTime: 12/20/2014 5:06:44 PM
Tuple`2: (23, True)