将TimeSpan值序列化和反序列化为Object类型的属性 [英] Serializing and deserializing TimeSpan values to a property of type Object

查看:195
本文介绍了将TimeSpan值序列化和反序列化为Object类型的属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类,该类的字段类型为Object,其中可能包含TimeSpan对象.

I have a class that has a field of type Object that may contain a TimeSpan object.

我正在对此序列化和反序列化:

I am serializing this and the deserializing this:

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);

当我这样做时,duplicateObject.myTimeSpan包含字符串"2:00:00".

And when I do, duplicateObject.myTimeSpan contains the string "2:00:00".

如何获取反序列化为TimeSpan对象的数据?

How can I get this to deserialize into a TimeSpan object?

两点:

  1. 我不处理在其他地方已序列化的字符串.我要反序列化的唯一字符串是我序列化的字符串.
  2. 该字段必须是object类型的-它可能包含字符串或DateTime,或者可能包含TimeSpan.目前,这只是我遇到问题的时间跨度.

推荐答案

Json.Net具有TypeNameHandling设置,用于处理未知类型,以便可以正确地反序列化它们.启用此设置后,它将导致Json.Net将特殊的$type属性插入JSON,然后在反序列化时将其用作提示.不幸的是,此设置似乎不适用于TimeSpan之类的简单"类型,因为它们的值被序列化为字符串而不是对象.

Json.Net has a TypeNameHandling setting for dealing with unknown types such that they can be deserialized properly. When this setting is turned on, it causes Json.Net to insert special $type properties into the JSON which are then used as hints when deserializing. Unfortunately, this setting does not seem to work with "simple" types such as TimeSpan, because their values are serialized as strings rather than objects.

要变通解决此问题,我建议创建一个使用相同想法的自定义JsonConverter.转换器将直接输出具有两个属性的子对象表示形式:typevalue,而不是直接输出对象的字符串值.子对象的type属性将包含该对象的程序集限定类型名称,而value属性将包含实际的序列化值.反序列化时,转换器将查找type属性,以从value属性中了解要实例化的对象类型.这种方法的好处是您不必在模型类中添加任何其他属性或逻辑.

To work around this issue, I would suggest making a custom JsonConverter that uses the same idea. Instead of outputting the string value of the object directly, the converter would output a sub-object representation with two properties: type and value. The type property of the sub-object would contain the assembly-qualified type name for the object, while the value property would contain the actual serialized value. On deserialization, the converter would look for the type property to know what type of object to instantiate from the value property. The nice thing about this approach is you do not have to add any additional properties or logic to your model class(es).

这是它在代码中的外观:

Here is how it might look in code:

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);
    }
}

要使用转换器,只需使用以下[JsonConverter]属性装饰类中需要特殊处理的所有object属性:

To use the converter, just decorate any object properties in your classes that need special handling with a [JsonConverter] attribute like this:

public class MyObject
{
    [JsonConverter(typeof(UnknownObjectConverter))]
    public object MyValue { get; set; }
}

这是一个往返演示,展示了该演示如何在几种不同的类型上工作.

Here is a round-trip demo which shows how this can work for several different types.

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)

这篇关于将TimeSpan值序列化和反序列化为Object类型的属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆