Serializing null in JSON.NET

后端 未结 1 1930
余生分开走
余生分开走 2020-11-29 01:40

When serializing arbitrary data via JSON.NET, any property that is null is written to the JSON as

\"propertyName\" : null

This

相关标签:
1条回答
  • 2020-11-29 02:26

    Okay, I think I've come up with a solution (my first solution wasn't right at all, but then again I was on the train). You need to create a special contract resolver and a custom ValueProvider for Nullable types. Consider this:

    public class NullableValueProvider : IValueProvider
    {
        private readonly object _defaultValue;
        private readonly IValueProvider _underlyingValueProvider;
    
    
        public NullableValueProvider(MemberInfo memberInfo, Type underlyingType)
        {
            _underlyingValueProvider = new DynamicValueProvider(memberInfo);
            _defaultValue = Activator.CreateInstance(underlyingType);
        }
    
        public void SetValue(object target, object value)
        {
            _underlyingValueProvider.SetValue(target, value);
        }
    
        public object GetValue(object target)
        {
            return _underlyingValueProvider.GetValue(target) ?? _defaultValue;
        }
    }
    
    public class SpecialContractResolver : DefaultContractResolver
    {
        protected override IValueProvider CreateMemberValueProvider(MemberInfo member)
        {
            if(member.MemberType == MemberTypes.Property)
            {
                var pi = (PropertyInfo) member;
                if (pi.PropertyType.IsGenericType && pi.PropertyType.GetGenericTypeDefinition() == typeof (Nullable<>))
                {
                    return new NullableValueProvider(member, pi.PropertyType.GetGenericArguments().First());
                }
            }
            else if(member.MemberType == MemberTypes.Field)
            {
                var fi = (FieldInfo) member;
                if(fi.FieldType.IsGenericType && fi.FieldType.GetGenericTypeDefinition() == typeof(Nullable<>))
                    return new NullableValueProvider(member, fi.FieldType.GetGenericArguments().First());
            }
    
            return base.CreateMemberValueProvider(member);
        }
    }
    

    Then I tested it using:

    class Foo
    {
        public int? Int { get; set; }
        public bool? Boolean { get; set; }
        public int? IntField;
    }
    

    And the following case:

    [TestFixture]
    public class Tests
    {
        [Test]
        public void Test()
        {
            var foo = new Foo();
    
            var settings = new JsonSerializerSettings { ContractResolver = new SpecialContractResolver() };
    
            Assert.AreEqual(
                JsonConvert.SerializeObject(foo, Formatting.None, settings), 
                "{\"IntField\":0,\"Int\":0,\"Boolean\":false}");
        }
    }
    

    Hopefully this helps a bit...

    Edit – Better identification of the a Nullable<> type

    Edit – Added support for fields as well as properties, also piggy-backing on top of the normal DynamicValueProvider to do most of the work, with updated test

    0 讨论(0)
提交回复
热议问题