【问题标题】:Why Json.net does not use customized IsoDateTimeConverter?为什么 Json.net 不使用自定义的 IsoDateTimeConverter?
【发布时间】:2011-09-17 01:38:01
【问题描述】:

我使用Json.net 序列化我的对象,我想自定义DateTime 输出:

这是一个小例子:

[DataContract]
class x
{
    [DataMember]
    [JsonConverter(typeof(IsoDateTimeConverter))]
    public DateTime datum = new DateTime(1232, 3, 23);
}

var dtc = new IsoDateTimeConverter();
dtc.DateTimeFormat = "yy";
JsonConvert.SerializeObject(new x(), dtc);

结果是{"datum":"1232-03-23T00:00:00"} 而不是{"datum":"1232"}

这可以正常工作(返回"32"):

return JsonConvert.SerializeObject(new DateTime(1232, 3, 23), dtc);

问题在哪里?

【问题讨论】:

    标签: datetime json.net converter


    【解决方案1】:

    问题是通过[JsonConverter(typeof(IsoDateTimeConverter))] 应用的转换器取代 传递给序列化程序的转换器。这记录在Serialization Attributes: JsonConverterAttribute:

    JsonConverterAttribute 指定哪个 JsonConverter 用于转换对象。

    属性可以放在类或成员上。当放置在 类,该属性指定的 JsonConverter 将是 序列化该类的默认方式。当属性在 字段或属性,则指定的 JsonConverter 将始终为 用于序列化该值。

    使用JsonConverter的优先级是成员属性,那么 类属性,最后是传递给 JsonSerializer。

    作为一种解决方法,在应用转换器的ReadJson()WriteJson() 方法中,可以在序列化程序的转换器列表中检查相关转换器,如果找到,则使用它。装饰器模式可用于将此逻辑与底层转换逻辑分开。一、介绍:

    public class OverridableJsonConverterDecorator : JsonConverterDecorator
    {
        public OverridableJsonConverterDecorator(Type jsonConverterType) : base(jsonConverterType) { }
    
        public OverridableJsonConverterDecorator(JsonConverter converter) : base(converter) { }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            foreach (var converter in serializer.Converters)
            {
                if (converter == this)
                {
                    Debug.WriteLine("Skipping identical " + converter.ToString());
                    continue;
                }
                if (converter.CanConvert(value.GetType()) && converter.CanWrite)
                {
                    converter.WriteJson(writer, value, serializer);
                    return;
                }
            }
            base.WriteJson(writer, value, serializer);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            foreach (var converter in serializer.Converters)
            {
                if (converter == this)
                {
                    Debug.WriteLine("Skipping identical " + converter.ToString());
                    continue;
                }
                if (converter.CanConvert(objectType) && converter.CanRead)
                {
                    return converter.ReadJson(reader, objectType, existingValue, serializer);
                }
            }
            return base.ReadJson(reader, objectType, existingValue, serializer);
        }
    }
    
    public abstract class JsonConverterDecorator : JsonConverter
    {
        readonly JsonConverter converter;
    
        public JsonConverterDecorator(Type jsonConverterType) : this((JsonConverter)Activator.CreateInstance(jsonConverterType)) { }
    
        public JsonConverterDecorator(JsonConverter converter)
        {
            if (converter == null)
                throw new ArgumentNullException();
            this.converter = converter;
        }
    
        public override bool CanConvert(Type objectType)
        {
            return converter.CanConvert(objectType);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            return converter.ReadJson(reader, objectType, existingValue, serializer);
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            converter.WriteJson(writer, value, serializer);
        }
    
        public override bool CanRead { get { return converter.CanRead; } }
    
        public override bool CanWrite { get { return converter.CanWrite; } }
    }
    

    然后,将装饰器应用到IsoDateTimeConverter 之上,如下所示:

    [DataContract]
    class x
    {
        [DataMember]
        [JsonConverter(typeof(OverridableJsonConverterDecorator), typeof(IsoDateTimeConverter))]
        public DateTime datum = new DateTime(1232, 3, 23);
    }
    

    现在静态应用的转换器将根据需要被取代。示例fiddle

    请注意,对于这个特定的测试用例,从Json.NET 4.5.1 开始,日期默认在 ISO 中序列化,并且不再需要 IsoDateTimeConverter。强制日期以特定格式序列化可以通过设置JsonSerializerSettings.DateFormatString来完成:

    [DataContract]
    class x
    {
        [DataMember]
        public DateTime datum = new DateTime(1232, 3, 23);
    }
    
    var settings = new JsonSerializerSettings { DateFormatString = "yy" };
    var json1 = JsonConvert.SerializeObject(new x(), settings);
    Console.WriteLine(json1); // Prints {"datum":"32"}
    
    var json2 = JsonConvert.SerializeObject(new x());
    Console.WriteLine(json2); // Prints {"datum":"1232-03-23T00:00:00"}
    

    示例fiddle。不过,一般问题值得回答。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-09-03
      • 1970-01-01
      • 1970-01-01
      • 2016-03-03
      • 1970-01-01
      • 1970-01-01
      • 2015-07-03
      相关资源
      最近更新 更多