gpt4 book ai didi

c# - 使用自定义 ContractResolver,如何在将 null JSON 属性反序列化为值类型成员时设置默认值而不是 null?

转载 作者:行者123 更新时间:2023-11-30 22:59:20 31 4
gpt4 key购买 nike

这是我到目前为止所得到的。感谢Brian Rodgers :

public class JsonSerializeTest
{
[Fact]
public void deserialize_test()
{
var settings = new JsonSerializerSettings { ContractResolver = new CustomContractResolver() };

var jsonString = "{\"PropertyA\":\"Test\",\"PropertyB\":null}";
var jsonObject = JsonConvert.DeserializeObject<NoConfigModel>(jsonString, settings);
Assert.NotNull(jsonObject);

}
}

public class NoConfigModel
{
public string PropertyA { get; set; }
public int PropertyB { get; set; }
public bool PropertyC { get; set; }

}

class CustomContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
property.ShouldDeserialize = instance =>
{
try
{
PropertyInfo prop = (PropertyInfo)member;
if (prop.CanRead)
{
var value = prop.GetValue(instance, null);// getting default value(0) here instead of null for PropertyB
return value != null;
}
}
catch
{
}
return false;
};
return property;
}
}

我的问题:

需要将默认值设置为 Not Nullable 字段,而不是 Exception 或整个对象为 null。缺少值不是问题(通过 DefaultContractResolver 给出默认值),但是当在 json 中将不可空值显式设置为 null 时,则会出现异常。

我上面的代码很接近但不够接近。我想我需要找到一种方法来从 json 中知道该值实际上为空,并为这些情况设置 ShouldDeserialize =false

最佳答案

你想要的是,在反序列化过程中,当一个 null遇到不可为 null 的成员的值,以在包含的对象中设置一个默认(非 null)值。这可以通过覆盖 DefaultContractResolver.CreateProperty 来完成如下:

class CustomContractResolver : DefaultContractResolver
{
class NullToDefaultValueProvider : ValueProviderDecorator
{
readonly object defaultValue;

public NullToDefaultValueProvider(IValueProvider baseProvider, object defaultValue) : base(baseProvider)
{
this.defaultValue = defaultValue;
}

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

protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property != null && property.PropertyType.IsValueType && Nullable.GetUnderlyingType(property.PropertyType) == null && property.Writable)
{
var defaultValue = property.DefaultValue ?? Activator.CreateInstance(property.PropertyType);

// When a null value is encountered in the JSON we want to set a default value in the class.
property.PropertyType = typeof(Nullable<>).MakeGenericType(new[] { property.PropertyType });
property.ValueProvider = new NullToDefaultValueProvider(property.ValueProvider, defaultValue);

// Remember that the underlying property is actually not nullable so GetValue() will never return null.
// Thus the below just overrides JsonSerializerSettings.NullValueHandling to force the value to be set
// (to the default) even when null is encountered.
property.NullValueHandling = NullValueHandling.Include;
}
return property;
}

// As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons.
// http://www.newtonsoft.com/json/help/html/ContractResolver.htm
// http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm
// "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance."
// See also https://stackoverflow.com/questions/33557737/does-json-net-cache-types-serialization-information
static CustomContractResolver instance;

// Explicit static constructor to tell C# compiler not to mark type as beforefieldinit
static CustomContractResolver() { instance = new CustomContractResolver(); }

public static CustomContractResolver Instance { get { return instance; } }

}

public abstract class ValueProviderDecorator : IValueProvider
{
readonly IValueProvider baseProvider;

public ValueProviderDecorator(IValueProvider baseProvider)
{
if (baseProvider == null)
throw new ArgumentNullException();
this.baseProvider = baseProvider;
}

public virtual object GetValue(object target) { return baseProvider.GetValue(target); }

public virtual void SetValue(object target, object value) { baseProvider.SetValue(target, value); }
}

注意事项:

工作示例 .Net fiddle here .

关于c# - 使用自定义 ContractResolver,如何在将 null JSON 属性反序列化为值类型成员时设置默认值而不是 null?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52276856/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com