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);
}
您还可以将默认值设置为:
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);
}
}
我正在使用 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);
}
您还可以将默认值设置为:
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);
}
}