使用Json.Net进行自定义DateTime序列化

3

我试图创建一个自定义的DateTime转换器,但没有成功。 问题是:我有许多要序列化的对象,其中一些包含DateTime.MinValue属性。我想将其序列化为null。但所有我找到的解决方案都要求在对象内部装饰proper(我无法这样做)。 另一个我找到的解决方案是创建转换器,据我所知,这个转换器仅适用于显式返回DateTime对象而不适用于其他对象中的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.");
    }
3个回答

5

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

这是一个简单的转换器,可以完成你想要的功能:

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
  ]
}

1
当转换器实现了CanConvert(你的也是这样),你可以将其添加到序列化器设置中:
JsonConvert.SerializeObject(foo, new JsonSerializerSettings {
    Converters = {
        new DateTimeConverter()
    }
});

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


0

找到了我的问题答案。实际上我在JsonSerializer设置中有两个转换器。 当我移除了包含DateTime MinValue属性的对象A上的转换器时,我注意到我的序列化程序可以正常工作。这让我明白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!");
    }


}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接