在 Json.net 反序列化中强制构造函数参数值
Force constructor parameter value in Json.net deserialization
是否可以强制 Json.net 为构造函数参数传递默认值?
我尝试使用自定义 ContractResolver
覆盖 CreateConstructorParameters
和 CreatePropertyFromConstructorParameter
方法并将返回的 JsonProperty.DefaultValue
属性 设置为我想要的值,并且DefaultValueHandling
属性 到 DefaultValueHandling.Populate
。
通过覆盖 CreateObjectContract
方法,我可以看到匹配的 CreatorParameters
和 Properties
都包含我的默认值。但是,我仍然得到传递给构造函数的 null
值。
我什至尝试将属性上的 Converter
设置为仅 returns 所需默认值的转换器,但仍然没有成功。
ConstractResolver代码如下:
public class DataControllerContractResolver : DefaultContractResolver
{
///The desired default value
private readonly IDataController _dataController;
private readonly Type _dataControllerType;
private readonly JsonConverter<IDataController> _converter;
public DataControllerContractResolver(IDataController dataController)
{
_dataController = dataController;
_dataControllerType = dataController.GetType();
_converter = SimpleJsonConverter<IDataController>.From((reader, controller, arg3) => _dataController, (writer, controller, arg3) => {});
}
protected override IList<JsonProperty> CreateConstructorParameters(ConstructorInfo constructor, JsonPropertyCollection memberProperties)
{
var props = base.CreateConstructorParameters(constructor, memberProperties);
foreach (var prop in memberProperties.Where(p => p.PropertyType.IsAssignableFrom(_dataControllerType)).ToList())
{
prop.DefaultValue = _dataController;
prop.Converter = _converter;
prop.DefaultValueHandling = DefaultValueHandling.Populate;
prop.Ignored = false;
}
foreach (var prop in props.Where(p => p.PropertyType.IsAssignableFrom(_dataControllerType)).ToList())
{
prop.DefaultValue = _dataController;
prop.Converter = _converter;
prop.DefaultValueHandling = DefaultValueHandling.Populate;
prop.Ignored = false;
}
return props;
}
protected override JsonProperty CreatePropertyFromConstructorParameter(JsonProperty matchingMemberProperty, ParameterInfo parameterInfo)
{
var prop = base.CreatePropertyFromConstructorParameter(matchingMemberProperty, parameterInfo);
if (prop.PropertyType.IsAssignableFrom(_dataControllerType))
{
prop.DefaultValue = _dataController;
prop.Converter = _converter;
prop.MemberConverter = _converter;
prop.DefaultValueHandling = DefaultValueHandling.Populate;
prop.Ignored = false;
}
return prop;
}
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
return contract;
}
}
如果我覆盖 property.DefaultValue
and property.DefaultValueHandling
in CreateProperties(Type type, MemberSerialization memberSerialization)
,我可以完成这项工作。我没有你所有的 classes(没有 IDataController
),所以这里有一个简单的例子:
public class DefaultStringValueContractResolver : DefaultContractResolver
{
public string DefaultStringValue { get; set; }
public DefaultStringValueContractResolver(string defaultStringValue)
{
this.DefaultStringValue = defaultStringValue;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
// Set all string properties to have a default value of "this is a default value"
foreach (var property in properties.Where(p => p.PropertyType == typeof(string)))
{
property.DefaultValue = DefaultStringValue;
property.DefaultValueHandling = DefaultValueHandling.Populate;
}
return properties;
}
}
然后:
public class TestClass
{
const string DefaultStringValue = "This is a default string value";
public string Property1 { get; set; }
public string Property2 { get; set; }
public static void Test()
{
var settings = new JsonSerializerSettings { ContractResolver = new DefaultStringValueContractResolver(DefaultStringValue) };
var test = JsonConvert.DeserializeObject<TestClass>("{}", settings);
Debug.Assert(test.Property1 == DefaultStringValue && test.Property2 == DefaultStringValue); // No assert
Debug.WriteLine(JsonConvert.SerializeObject(test)); // Prints {"Property1":"This is a default string value","Property2":"This is a default string value"}
}
}
需要注意的一件事:如果默认值是引用类型,则包含 属性 的 class 的所有实例都将具有引用相同默认值实例的默认值。
在找不到针对此问题的内置解决方案后,我全力以赴并添加了默认值检查和 pull-request on Github. JamesNK (the Json.net creator) implemented the solution 略有不同,但它在最新版本中可用。
是否可以强制 Json.net 为构造函数参数传递默认值?
我尝试使用自定义 ContractResolver
覆盖 CreateConstructorParameters
和 CreatePropertyFromConstructorParameter
方法并将返回的 JsonProperty.DefaultValue
属性 设置为我想要的值,并且DefaultValueHandling
属性 到 DefaultValueHandling.Populate
。
通过覆盖 CreateObjectContract
方法,我可以看到匹配的 CreatorParameters
和 Properties
都包含我的默认值。但是,我仍然得到传递给构造函数的 null
值。
我什至尝试将属性上的 Converter
设置为仅 returns 所需默认值的转换器,但仍然没有成功。
ConstractResolver代码如下:
public class DataControllerContractResolver : DefaultContractResolver
{
///The desired default value
private readonly IDataController _dataController;
private readonly Type _dataControllerType;
private readonly JsonConverter<IDataController> _converter;
public DataControllerContractResolver(IDataController dataController)
{
_dataController = dataController;
_dataControllerType = dataController.GetType();
_converter = SimpleJsonConverter<IDataController>.From((reader, controller, arg3) => _dataController, (writer, controller, arg3) => {});
}
protected override IList<JsonProperty> CreateConstructorParameters(ConstructorInfo constructor, JsonPropertyCollection memberProperties)
{
var props = base.CreateConstructorParameters(constructor, memberProperties);
foreach (var prop in memberProperties.Where(p => p.PropertyType.IsAssignableFrom(_dataControllerType)).ToList())
{
prop.DefaultValue = _dataController;
prop.Converter = _converter;
prop.DefaultValueHandling = DefaultValueHandling.Populate;
prop.Ignored = false;
}
foreach (var prop in props.Where(p => p.PropertyType.IsAssignableFrom(_dataControllerType)).ToList())
{
prop.DefaultValue = _dataController;
prop.Converter = _converter;
prop.DefaultValueHandling = DefaultValueHandling.Populate;
prop.Ignored = false;
}
return props;
}
protected override JsonProperty CreatePropertyFromConstructorParameter(JsonProperty matchingMemberProperty, ParameterInfo parameterInfo)
{
var prop = base.CreatePropertyFromConstructorParameter(matchingMemberProperty, parameterInfo);
if (prop.PropertyType.IsAssignableFrom(_dataControllerType))
{
prop.DefaultValue = _dataController;
prop.Converter = _converter;
prop.MemberConverter = _converter;
prop.DefaultValueHandling = DefaultValueHandling.Populate;
prop.Ignored = false;
}
return prop;
}
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
return contract;
}
}
如果我覆盖 property.DefaultValue
and property.DefaultValueHandling
in CreateProperties(Type type, MemberSerialization memberSerialization)
,我可以完成这项工作。我没有你所有的 classes(没有 IDataController
),所以这里有一个简单的例子:
public class DefaultStringValueContractResolver : DefaultContractResolver
{
public string DefaultStringValue { get; set; }
public DefaultStringValueContractResolver(string defaultStringValue)
{
this.DefaultStringValue = defaultStringValue;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
// Set all string properties to have a default value of "this is a default value"
foreach (var property in properties.Where(p => p.PropertyType == typeof(string)))
{
property.DefaultValue = DefaultStringValue;
property.DefaultValueHandling = DefaultValueHandling.Populate;
}
return properties;
}
}
然后:
public class TestClass
{
const string DefaultStringValue = "This is a default string value";
public string Property1 { get; set; }
public string Property2 { get; set; }
public static void Test()
{
var settings = new JsonSerializerSettings { ContractResolver = new DefaultStringValueContractResolver(DefaultStringValue) };
var test = JsonConvert.DeserializeObject<TestClass>("{}", settings);
Debug.Assert(test.Property1 == DefaultStringValue && test.Property2 == DefaultStringValue); // No assert
Debug.WriteLine(JsonConvert.SerializeObject(test)); // Prints {"Property1":"This is a default string value","Property2":"This is a default string value"}
}
}
需要注意的一件事:如果默认值是引用类型,则包含 属性 的 class 的所有实例都将具有引用相同默认值实例的默认值。
在找不到针对此问题的内置解决方案后,我全力以赴并添加了默认值检查和 pull-request on Github. JamesNK (the Json.net creator) implemented the solution 略有不同,但它在最新版本中可用。