JSON.net 缺失属性的默认值

Default value for missing properties with JSON.net

我正在使用 Json.net 将对象序列化到数据库。

我向 class 添加了一个新的 属性(在数据库的 json 中丢失了)并且我希望新的 属性 具有默认值json.

中缺失时的值

我尝试了 DefaultValue 属性,但它不起作用。我正在使用私有 setter 和构造函数来反序列化 json,因此在构造函数中设置 属性 的值将不起作用,因为存在一个具有该值的参数。

示例如下:

    class Cat
    {
        public Cat(string name, int age)
        {
            Name = name;
            Age = age;
        }

        public string Name { get; private set; }

        [DefaultValue(5)]            
        public int Age { get; private set; }
    }

    static void Main(string[] args)
    {
        string json = "{\"name\":\"mmmm\"}";

        Cat cat = JsonConvert.DeserializeObject<Cat>(json);

        Console.WriteLine("{0} {1}", cat.Name, cat.Age);
    }

我预计年龄是 5 岁,但它是零。

有什么建议吗?

我找到了答案,只需要添加以下属性:

[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]

在你的例子中:

class Cat
{
    public Cat(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public string Name { get; private set; }

    [DefaultValue(5)]            
    [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
    public int Age { get; private set; }
}

static void Main(string[] args)
{
    string json = "{\"name\":\"mmmm\"}";

    Cat cat = JsonConvert.DeserializeObject<Cat>(json);

    Console.WriteLine("{0} {1}", cat.Name, cat.Age);
}

Json.Net Reference

您还可以将默认值设置为:

class Cat
{           
    public string Name { get; set; }
        
    public int Age { get; set; } = 1 ; // one is the default value. If json property does not exist when deserializing the value will be one. 
}

添加 [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] ,将您的年龄从

更改为 属性
    [DefaultValue(5)]            
    public int Age { get; private set; }

    [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
    [DefaultValue(5)]
    public string Age { get; private set; }

我遇到了与已经描述过的人相同的问题,可能是现有构造函数导致 DefaultValueHandling 无法正常工作。我玩了一下,发现可以使用 NullValueHandling 绕过它。

[DefaultValue(5)]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate, NullValueHandling = NullValueHandling.Ignore)]
public int Age { get; set; }

由于问题的标题措辞更广泛(不仅仅是处理 单个 默认值 单个 缺失 JSON 属性),这里有一个更通用的解决方案,用于在全局级别处理缺失的 JSON 属性:

要处理更复杂模型中 所有 缺失的 JSON 属性,可能需要 ContractResolver。 (其他方式与一般的缺失属性或空值处理不一致)

想法是使用 DefaultContractResolver.CreateProperty()“挂钩”到 JSON 属性的创建并指定所需的行为,这将 运行 与所有成员(包括嵌套成员)相关在(反)序列化过程中:

public class MyContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty prop = base.CreateProperty(member, memberSerialization);

        // do smth with the property (settings) here

        return prop;
    }
}

这是一个示例,说明如何在 default-initialize 所有 collection 类型缺失时将它们清空而不是空值(最初让我想到的是这个问题):

public class EmptyCollectionJsonResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty prop = base.CreateProperty(member, memberSerialization);

        // default initialize collections to empty instead of null
        if (IsCollection(prop.PropertyType))
        {
            prop.DefaultValue = Activator.CreateInstance(prop.PropertyType); // creates empty collection
            prop.DefaultValueHandling = DefaultValueHandling.Populate; // force population on null / missing parsed members
        }

        return prop;
    }

    // helper function to determine if a type is a collection
    private static readonly Type TColl = typeof(ICollection<>);
    private static bool IsCollection(Type t)
    {
        return t.IsGenericType 
            && TColl.IsAssignableFrom(t.GetGenericTypeDefinition()) || t.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == TColl);
    }
}