为什么Json.net不使用自定义的IsoDateTimeConverter?

为什么Json.net不使用自定义的IsoDateTimeConverter?,datetime,json.net,converter,Datetime,Json.net,Converter,我使用Json.net来序列化我的对象,我想定制DateTime输出: 下面是一个小例子: [DataContract] class x { [DataMember] [JsonConverter(typeof(IsoDateTimeConverter))] public DateTime datum = new DateTime(1232, 3, 23); } var dtc = new IsoDateTimeConverter(); dtc.DateTimeForm

我使用
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”
):


捕获项在哪里?

捕获项是通过
[JsonConverter(typeof(IsoDateTimeConverter))]应用的转换器。
取代传递到序列化程序中的转换器。这记录在:

指定哪个 用于转换对象

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

使用JsonConverter的优先级是member属性,然后 类属性,最后是传递给 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);
}
现在,静态应用转换器将根据需要被取代。样品

注意,对于这个特定的测试用例,“截止日期”默认情况下在ISO中序列化,不再需要
IsoDateTimeConverter
。强制以特定格式序列化日期可以通过设置:

样品。然而,一般性问题值得回答

[DataContract]
class x
{
    [DataMember]
    [JsonConverter(typeof(OverridableJsonConverterDecorator), typeof(IsoDateTimeConverter))]
    public DateTime datum = new DateTime(1232, 3, 23);
}
[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"}