Подвох состоит в том, что преобразователь, примененный через [JsonConverter(typeof(IsoDateTimeConverter))]
, заменяет преобразователь, переданный в сериализатор. Это задокументировано в Атрибуты сериализации: JsonConverterAttribute :
The
JsonConverterAttribute
указывает, какой
JsonConverter
используется для преобразования объекта.
Атрибут может быть помещен в класс или член. Когда помещено на
класс, 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);
}
Теперь статически применяемый конвертер будет заменен по мере необходимости. Образец скрипка .
Обратите внимание, что для этого конкретного контрольного примера с даты 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"}
Образец Скрипка . Тем не менее общий вопрос заслуживает ответа.