C# 如何在列表序列化期间将空JSON属性默认为空数组<;T>;JSON.NET中的属性?

C# 如何在列表序列化期间将空JSON属性默认为空数组<;T>;JSON.NET中的属性?,c#,arrays,json.net,C#,Arrays,Json.net,目前我使用的JSON要么通过HTTP调用传入,要么存储在数据库中,但在服务器处理过程中,它们被映射到C#对象 这些对象具有类似于公共列表MyArray的属性 当JSON包含MyArray:null时,我希望结果属性是空的List而不是空的List属性 目标是该对象将以MyArray:[]的形式“重新序列化”为JSON,从而保存到数据库或通过HTTP作为空数组而不是null响应 这样,不管怎样,C#类基本上是为任何列表属性清理和强制执行空数组,否则这些属性将为null,并导致浏览器端代码中断(例如

目前我使用的JSON要么通过HTTP调用传入,要么存储在数据库中,但在服务器处理过程中,它们被映射到C#对象

这些对象具有类似于
公共列表MyArray
的属性

当JSON包含
MyArray:null
时,我希望结果属性是空的
List
而不是空的
List
属性

目标是该对象将以
MyArray:[]
的形式“重新序列化”为JSON,从而保存到数据库或通过HTTP作为空数组而不是
null
响应

这样,不管怎样,C#类基本上是为任何
列表
属性清理和强制执行空数组,否则这些属性将为
null
,并导致浏览器端代码中断(例如:
无法读取null
的属性“length”)


在序列化/反序列化过程中,有没有一种方法可以使与
列表
属性配对的任何空值变为空数组?

如果空列表为null,则始终可以延迟加载空列表

在JsonDeserializer上使用NullValueHandling选项

var settings = new JsonSerializerSettings();
settings.NullValueHandling = NullValueHandling.Ignore;

return JsonConvert.DeserializeObject<T>(json, settings);
var settings=newjsonserializersettings();
settings.NullValueHandling=NullValueHandling.Ignore;
返回JsonConvert.DeserializeObject(json,设置);

我打算建议使用一个定制的
JsonConverter
来解决这个问题,但是对于空值不会调用转换器。相反,您需要将自定义
IContractResolver
与自定义
IValueProvider
结合使用。以下是您需要的代码(灵感来源):


要在.net核心解决方案中使用Brian Rogers解决方案,您需要对“IsGenericType”属性进行轻微修改,以便在它从Type移动到TypeInfo时访问它

标记为正确的答案(设置NullValueHandling)对我不起作用,如果该属性为null,它将忽略该属性

.net核心的完整代码:

using System;
using System.Collections.Generic;
using Newtonsoft.Json.Serialization;
using System.Reflection;

public class NullToEmptyListResolver : DefaultContractResolver
{
    protected override IValueProvider CreateMemberValueProvider(MemberInfo member)
    {
        IValueProvider provider = base.CreateMemberValueProvider(member);

        if (member.MemberType == MemberTypes.Property)
        {
            Type propType = ((PropertyInfo)member).PropertyType;
            TypeInfo propTypeInfo = propType.GetTypeInfo();
            if (propTypeInfo.IsGenericType &&
                propType.GetGenericTypeDefinition() == typeof(List<>))
            {
                return new EmptyListValueProvider(provider, propType);
            }
        }

        return provider;
    }

    class EmptyListValueProvider : IValueProvider
    {
        private IValueProvider innerProvider;
        private object defaultValue;

        public EmptyListValueProvider(IValueProvider innerProvider, Type listType)
        {
            this.innerProvider = innerProvider;
            defaultValue = Activator.CreateInstance(listType);
        }

        public void SetValue(object target, object value)
        {
            innerProvider.SetValue(target, value ?? defaultValue);
        }

        public object GetValue(object target)
        {
            return innerProvider.GetValue(target) ?? defaultValue;
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用Newtonsoft.Json.Serialization;
运用系统反思;
公共类NullToEmptyListResolver:DefaultContractResolver
{
受保护的覆盖IValueProvider CreateMemberValueProvider(MemberInfo成员)
{
IValueProvider provider=base.CreateMemberValueProvider(成员);
if(member.MemberType==MemberTypes.Property)
{
类型propType=((PropertyInfo)成员);
TypeInfo-propTypeInfo=propType.GetTypeInfo();
如果(propTypeInfo.IsGenericType&&
propType.GetGenericTypeDefinition()==typeof(列表))
{
返回新的EmptyListValueProvider(provider,propType);
}
}
退货供应商;
}
类EmptyListValueProvider:IValueProvider
{
私人供应商;
私有客体价值;
public EmptyListValueProvider(IValueProvider innerProvider,类型listType)
{
this.innerProvider=innerProvider;
defaultValue=Activator.CreateInstance(listType);
}
public void SetValue(对象目标、对象值)
{
SetValue(目标,值??默认值);
}
公共对象GetValue(对象目标)
{
返回innerProvider.GetValue(目标)??默认值;
}
}
}

在这两种情况下,反序列化后,以下属性将分配空集合,而不是
null
:在JSON中省略该属性或显式设置为
null
时:

class A
{
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public IEnumerable<int> Prop { get; set; } = new List<int>();
}
A类
{
[JsonProperty(NullValueHandling=NullValueHandling.Ignore)]
public IEnumerable Prop{get;set;}=new List();
}

在查看了备选方案后,我将按照您最初的建议,只定义我自己的getter,如果您愿意,您可以将代码示例放回给未来的读者。当列表属性存在/有任何数据时,这似乎不会反序列化;在这种情况下,它们被反序列化为null。您的示例不会往返(尝试反序列化原始序列化的结果)。有什么想法吗?我真的很喜欢这种方法,但它不起作用——我需要json源代码中的一个数组,该数组为null以反序列化为空列表,但该数组中的数据要用所述数据反序列化为该列表。@pinkfloydx33您是对的——您需要将
ObjectCreationHandling
设置为
Replace
,才能使往返正常工作。我已经修改了我的答案。这里有一把小提琴来证明它的工作,一旦这个设置被添加:酷,谢谢!我原以为我会发疯,直到我一字不差地尝试了你的代码,然后尝试了往返。非常感谢
Serializing object with null lists...
{
  "IntList": [],
  "StringList": []
}

Deserializing JSON with null lists...
IntList size: 0
StringList size: 0
using System;
using System.Collections.Generic;
using Newtonsoft.Json.Serialization;
using System.Reflection;

public class NullToEmptyListResolver : DefaultContractResolver
{
    protected override IValueProvider CreateMemberValueProvider(MemberInfo member)
    {
        IValueProvider provider = base.CreateMemberValueProvider(member);

        if (member.MemberType == MemberTypes.Property)
        {
            Type propType = ((PropertyInfo)member).PropertyType;
            TypeInfo propTypeInfo = propType.GetTypeInfo();
            if (propTypeInfo.IsGenericType &&
                propType.GetGenericTypeDefinition() == typeof(List<>))
            {
                return new EmptyListValueProvider(provider, propType);
            }
        }

        return provider;
    }

    class EmptyListValueProvider : IValueProvider
    {
        private IValueProvider innerProvider;
        private object defaultValue;

        public EmptyListValueProvider(IValueProvider innerProvider, Type listType)
        {
            this.innerProvider = innerProvider;
            defaultValue = Activator.CreateInstance(listType);
        }

        public void SetValue(object target, object value)
        {
            innerProvider.SetValue(target, value ?? defaultValue);
        }

        public object GetValue(object target)
        {
            return innerProvider.GetValue(target) ?? defaultValue;
        }
    }
}
class A
{
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public IEnumerable<int> Prop { get; set; } = new List<int>();
}