【问题标题】:Custom DateTime serialization with Json.Net使用 Json.Net 自定义 DateTime 序列化
【发布时间】:2014-02-03 15:55:49
【问题描述】:

我正在尝试创建自定义 DateTime 转换器,但没有成功。 问题:我有很多对象要序列化,其中一些包含 DateTime 的属性,其中包含 DateTime.MinValue。我想将其序列化为空。但是我发现的所有解决方案都要求在对象内部进行适当的装饰(我做不到) 我在下面找到的其他解决方案是创建转换器,据我所知,此转换器仅适用于明确返回的 DateTime 对象,而不适用于其他对象。 请帮忙。

public class DateTimeConverter : JsonConverter
{
    private readonly Type[] types;

    public DateTimeConverter(params Type[] types)
    {
        this.types = types;
    }

    public override bool CanConvert(Type objectType)
    {
        return types.Any(t => t == objectType);
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        JToken t = JToken.FromObject(value);

        if (t.Type != JTokenType.Object)
        {
            if (value is DateTime && value.Equals(DateTime.MinValue))
            {
                t = JToken.FromObject(null);
                t.WriteTo(writer);
            }
            else
            {
                t.WriteTo(writer);
            }
        }
        else
        {
            if (value.Equals(DateTime.MinValue)) {
                t = JToken.FromObject(null);
                t.WriteTo(writer);
            }
            else {
                t.WriteTo(writer);
            }
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
    }

【问题讨论】:

    标签: c# serialization json.net


    【解决方案1】:

    我认为你把事情复杂化了。您的转换器应该只关心转换日期值,而不是可能包含日期值的对象。每当在任何其他对象中遇到日期时,序列化程序都会自然地调用您的转换器。

    这是一个简单的转换器,可以满足您的需求:

    public class MinDateToNullConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            // This converter handles date values directly
            return (objectType == typeof(DateTime));
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            // The CanConvert method guarantees the value will be a DateTime
            DateTime date = (DateTime)value;
            if (date == DateTime.MinValue)
            {
                writer.WriteNull();
            }
            else
            {
                writer.WriteValue(date);
            }
        }
    
        public override bool CanRead
        {
            get { return false; }
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
    

    这是一个演示,展示了转换器在对象嵌套层次结构中的日期上工作:

    class Program
    {
        static void Main(string[] args)
        {
            Example example = new Example
            {
                Date1 = new DateTime(2014, 2, 2),
                Date2 = DateTime.MinValue,
                Inner = new Inner
                {
                    DateA = DateTime.MinValue,
                    DateB = new DateTime(1954, 1, 26)
                },
                MoreDates = new List<DateTime>
                {
                    new DateTime(1971, 11, 15),
                    DateTime.MinValue
                }
            };
    
            // Set up the serializer to use our date converter
            JsonSerializerSettings settings = new JsonSerializerSettings();
            settings.Converters.Add(new MinDateToNullConverter());
            settings.Formatting = Formatting.Indented;
    
            string json = JsonConvert.SerializeObject(example, settings);
            Console.WriteLine(json);
        }
    }
    
    class Example
    {
        public DateTime Date1 { get; set; }
        public DateTime Date2 { get; set; }
        public Inner Inner { get; set; }
        public List<DateTime> MoreDates { get; set; }
    }
    
    class Inner
    {
        public DateTime DateA { get; set; }
        public DateTime DateB { get; set; }
    }
    

    输出:

    {
      "Date1": "2014-02-02T00:00:00",
      "Date2": null,
      "Inner": {
        "DateA": null,
        "DateB": "1954-01-26T00:00:00"
      },
      "MoreDates": [
        "1971-11-15T00:00:00",
        null
      ]
    }
    

    【讨论】:

      【解决方案2】:

      当转换器实现CanConvert(你的实现)时,你可以将它添加到序列化器设置中:

      JsonConvert.SerializeObject(foo, new JsonSerializerSettings {
          Converters = {
              new DateTimeConverter()
          }
      });
      

      这样,它将应用于它支持的所有对象。

      【讨论】:

      • 您的示例没有包含足够的信息来重现问题。见sscce.org。 “不起作用”也没有提供任何信息。转换器没有被调用吗?转换器会产生错误的值吗?生成的 JSON 不正确?什么?
      【解决方案3】:

      找到了我的问题的答案。实际上我在 JsonSerializer 设置中有 2 个转换器。 我注意到,当我删除对象 A 上包含 DateTime MinValue 属性的转换器时,我的序列化程序工作正常。这让我明白 DateTime 到 null 的转换器在其他转换器下不起作用。所以我所做的是在对象 A 转换器内手动转换,而不是完全干净的解决方案,我希望 DateTimeToNull 转换器也能在 A 转换器内工作。 这是我在 A 转换器中所做的:

          public class AConverter : JsonConverter
      {
      
          public override bool CanConvert(Type objectType)
          {
              return (objectType == typeof(A));
          }
      
          public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
          {
              JToken jToken = JToken.FromObject(value);
              JObject jObject = (JObject)jToken;
              A aInfo = (A) value;
              string statusString = aInfo.Status == null ? string.Empty : SomeUtil.GetStateString((State)aInfo.Status.State, aInfo.Status.Downloading);
              jObject.AddFirst(new JProperty("MachineState", statusString));
      
              if (aInfo.UploadTime == DateTime.MinValue) {
                  jObject.Remove("UploadTime");
                  jObject.Add(new JProperty("UploadTime", null));
              }
              jObject.WriteTo(writer);
          }
      
          public override bool CanRead
          {
              get
              {
                  return false;
              }
          }
      
          public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
          {
              throw new NotImplementedException("It's OK!");
          }
      
      
      }
      

      【讨论】:

        猜你喜欢
        • 2013-09-09
        • 2017-03-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多