2017-02-06 3 views
0

Есть ли способ указать пользовательскую десериализацию для сбора объектов, но только для дат?Newtonsoft.Json пользовательский набор объектов deserializer

Вот что я имею в виду:

Скажем, у меня есть коллекция предметов - это может быть любой объект и десериализации JSON их довольно хорошо. Все хорошо, а не даты.

public List<object> Values { get; set; } 

Я не хочу устанавливать какие-либо свойства по всему миру - но только для этого свойства. Если в коллекции значений есть DateTime - я хочу десериализовать его по-своему (например, без времени).

Что вы можете мне предложить?

Глобально я использовать эти настройки:

var settings = new Newtonsoft.Json.JsonSerializerSettings() 
{ 
    DateFormatHandling = Newtonsoft.Json.DateFormatHandling.IsoDateFormat, 
    DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc      
}; 

Использования:

К примеру у меня есть такая структура:

{ 
    "Intance": 1, 
    "Values": [ 
    "Ivan", 
    "488-555-1212", 
    "United States", 
    { 
     "ShortDesc": "NY", 
     "LongDesc": "New York" 
    }, 
    "1985-05-01T00:00:00-05:00" 
    ], 
    "LastUpdated": "2017-02-06T22:11:34-05:00" 
} 

Скажем - это дата рождения - «1985-05- 01T00: 00: 00-05: 00" . . Часовой пояс веб-служб - Восточное время: -5. Мой часовой пояс: Central Time (США): -6. В этом случае я получу: 1985-04-30 - День сзади. Это действительно так, но мне не нужно такое поведение. Свойство LastUpdated будет десериализоваться правильно.

+0

Я бы сериализовать как 'DateTime' и либо (а) передать результат в метод конвертер/конструктор для вашего STRUCT/типа или (б) игнорировать временную часть DateTime, определяя собственное сравнение и используя операторы формата при его отображении. Почему вы хотите сериализовать его без времени? –

+0

, например. это дата рождения ... Мне не нужна дата для этого. –

+0

Это хороший вопрос. На самом деле я думал об этом раньше. Предположим, сервер возвращает время в UTC. Как я могу автоматически конвертировать его в локальное время на стороне клиента при десериализации JSON для объекта? – Reynevan

ответ

0
[AttributeUsage(AttributeTargets.Property)] 
public class IgnoreTimeZoneAttribute : Attribute 
{ 
} 

public class IgnoreTimeZonePropertyResolver : DefaultContractResolver 
{ 
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) 
    { 
     IList<JsonProperty> props = base.CreateProperties(type, memberSerialization); 

     foreach (JsonProperty prop in props) 
     { 
      PropertyInfo pi = type.GetProperty(prop.UnderlyingName); 

      if (pi != null && pi.GetCustomAttribute(typeof(IgnoreTimeZoneAttribute), true) != null) 
      { 
       prop.ValueProvider = new IgnoreTimeZoneValueProvider(pi); 
      } 
     } 

     return props; 
    } 

    public class IgnoreTimeZoneValueProvider : IValueProvider 
    { 
     private PropertyInfo _targetProperty; 

     public IgnoreTimeZoneValueProvider(PropertyInfo targetProperty) 
     { 
      this._targetProperty = targetProperty; 
     } 

     // GetValue is called by Json.Net during serialization. 
     public object GetValue(object target) 
     { 
      return _targetProperty.GetValue(target); 
     } 

     // SetValue gets called by Json.Net during deserialization. 
     // The value parameter has the value/values read from the JSON; 
     // target is the object on which to set the value/values without TimeZone info. 
     public void SetValue(object target, object value) 
     { 
      var newValue = value; 

      if (typeof(IList).IsAssignableFrom(_targetProperty.PropertyType)) 
      { 
       IList<object> values = value as IList<object>; 

       if (values != null) 
       { 
        for (int i = 0; i < values.Count - 1; i++) 
        { 
         var curValue = values[i]; 
         if (curValue != null && curValue.GetType() == typeof(DateTime)) 
         { 
          DateTimeOffset dateTime = new DateTimeOffset((DateTime)curValue); 
          values[i] = dateTime.UtcDateTime.Date; 
         } 
        } 
       } 
      } 

      _targetProperty.SetValue(target, newValue); 
     } 
    } 
}