简体   繁体   English

Newtonsoft.Json 自定义对象集合反序列化器

[英]Newtonsoft.Json custom object collection deserializer

Is there any way to specify custom deserialization for collection of objects but only for dates?有什么方法可以为对象集合指定自定义反序列化,但仅限于日期?

Here is what do i mean:这是我的意思:

Let's say I have collection of objects - it could be any object and json deserialized them pretty good.假设我有对象集合 - 它可以是任何对象,并且 json 将它们反序列化得很好。 Everything is fine instead of dates.一切都很好,而不是日期。

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

I don't want to set any properties globally - but only for this property.我不想全局设置任何属性 - 但仅针对此属性。 If there is a DateTime in collection of Values - I want to deserialize it in my own way (eg without time).如果值集合中有 DateTime - 我想以我自己的方式反序列化它(例如没有时间)。

What can you suggest me?你能给我什么建议?

Globally i use this settings:我在全球范围内使用此设置:

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

Use Case:用例:

For instance I have such structure:例如我有这样的结构:

{
  "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"
}

Let's say - it is birthdate -让我们说 - 这是生日 -

"1985-05-01T00:00:00-05:00". “1985-05-01T00:00:00-05:00”。

Eg Web Services time zone - Eastern Time: -5 .例如 Web 服务时区 -东部时间:-5

My time zone is Central Time (US): -6 .我的时区是中部时间(美国): -6

In this case I will get: 1985-04-30 - It is day behind.在这种情况下,我会得到: 1985-04-30 - 它是一天后。 It is right, but I don't need such behavior, because it is my birthday and it shouldn't take into account time zones.这是对的,但我不需要这种行为,因为这是我的生日,不应该考虑时区。

LastUpdated property will deserialize correctly. LastUpdated 属性将正确反序列化。

I was able to make it work by adding custom contract resolver and custom attribute.我能够通过添加自定义合同解析器和自定义属性来使其工作。 So when resolver sees that attribute it deserializes date as expected.因此,当解析器看到该属性时,它会按预期反序列化日期。

[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);
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM