问题描述
我使用Json.net
序列化对象,并且想要自定义DateTime
输出:
I use Json.net
to serialize my objects and I want to customize DateTime
output:
这是一个小例子:
[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);
渔获物在哪里?
推荐答案
要注意的是,通过[JsonConverter(typeof(IsoDateTimeConverter))]
所应用的转换器取代了传递到序列化器中的转换器. 序列化属性:JsonConverterAttribute :
The catch is that the converter applied via [JsonConverter(typeof(IsoDateTimeConverter))]
supersedes the converter passed into the serializer. This is documented in Serialization Attributes: JsonConverterAttribute:
该属性可以放在类或成员上.当放在一个 类中,该属性指定的JsonConverter将是 序列化该类的默认方法.当属性位于 字段或属性,则指定的JsonConverter将始终为 用于序列化该值.
The attribute can be placed on a class or a member. When placed on a class, the JsonConverter specified by the attribute will be the default way of serializing that class. When the attribute is on a field or property, then the specified JsonConverter will always be used to serialize that value.
使用JsonConverter的优先级是成员属性,然后 class属性,最后将任何传递给 JsonSerializer.
The priority of which JsonConverter is used is member attribute, then class attribute, and finally any converters passed to the JsonSerializer.
作为一种解决方法,在所应用转换器的ReadJson()
和WriteJson()
方法中,可以在序列化器的转换器列表中检查相关的转换器,如果找到,请使用它.装饰器模式可用于将此逻辑与基础转换逻辑分开.首先,介绍:
As a workaround, in the ReadJson()
and WriteJson()
methods of the applied converter, one could check for a relevant converter in the serializer's list of converters, and if one is found, use it. The decorator pattern can be used to separate this logic from the underlying conversion logic. First, introduce:
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
顶部应用装饰器:
Then, apply the decorator on top of IsoDateTimeConverter
as follows:
[DataContract]
class x
{
[DataMember]
[JsonConverter(typeof(OverridableJsonConverterDecorator), typeof(IsoDateTimeConverter))]
public DateTime datum = new DateTime(1232, 3, 23);
}
现在,将根据需要替换静态应用的转换器.样本小提琴.
Now the statically applied converter will be superseded as required. Sample fiddle.
请注意,对于此特定测试用例,从 Json开始. NET 4.5.1 日期默认情况下在ISO中被序列化,并且不再需要IsoDateTimeConverter
.可以通过设置 JsonSerializerSettings.DateFormatString
:
Note that, for this specific test case, as of Json.NET 4.5.1 dates are serialized in ISO by default and IsoDateTimeConverter
is no longer required. Forcing dates to be serialized in a specific format can be accomplished by setting 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"}
示例小提琴.尽管如此,一般性问题还是值得回答的.
Sample fiddle. Nevertheless the general question deserves an answer.
这篇关于为什么Json.net不使用自定义的IsoDateTimeConverter?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!