JsonObjectContract.ParametrizedConstructor
被标记为已过时,并表示应使用OverrideCreator
。但是OverrideCreator
未设置_parametrizedConstructor
或_parameterizedCreator
,这意味着如果您需要从外部设置这些值,则必须使用ParametrizedConstructor
。
谢谢!
编辑1:
为了解释我问的原因,我的应用程序中有一个类来处理序列化(使用JSON.Net)。这个类创建了一个自定义IContractResolver
(基于DefaultContractResolver
),其库存集为JsonConverter
,我为我的应用程序编写。这允许生成的合同一次检查转换器然后被缓存。
我的序列化类允许调用者传入他们自己的自定义转换器。完成后,我创建一个新的IContractResolver
,它接受这些新的转换器和默认的合约解析器。我当时所做的是,在解决类型合同时,我首先从默认合约解析器中获得合同。当我得到它时,然后检查并查看是否有任何新转换器可以处理该类型。如果我们可以克隆' json合同并用新的转换器替换转换器(并缓存它)。
在此克隆中,我设置了ParametrizedConstructor
。我最初没有这样做,因为它被标记为已弃用,我只设置了OverrideCreator
。在反序列化Tuple
时,我遇到了一个问题。我一直收到一个错误,说没有Tuple的构造函数。我尝试使用股票JsonConvert
来往返Tuple
并且效果很好。在研究为什么它与JsonConvert
合作时,我发现这是因为当我克隆'合同我没有设置ParametrizedConstructor
。
编辑2:
这是我的合约解决方案的一个缩小的例子:
class MyContractResolver : DefaultContractResolver
{
readonly Dictionary<Type, JsonContract> contractDictionary = new Dictionary<Type, JsonContract>();
readonly List<JsonConverter> converters;
readonly IContractResolver resolverToExtend;
public MyContractResolver(List<JsonConverter> converters, IContractResolver resolverToExtend)
{
this.converters = converters;
this.resolverToExtend = resolverToExtend;
}
public override JsonContract ResolveContract(Type type)
{
JsonContract contract;
if (!contractDictionary.TryGetValue(type, out contract))
{
contract = resolverToExtend.ResolveContract(type);
var converter = contract.Converter;
foreach (var baseConverter in converters)
{
if (baseConverter.CanConvert(type))
{
contract = CloneJsonContract(contract, type, baseConverter);
break;
}
}
contractDictionary.Add(type, contract);
}
return contract;
}
static JsonContract CloneJsonContract(JsonContract contract, Type type, JsonConverter customConverter)
{
JsonContract newContract;
// Check contract type and create a new one (JsonArrayContract, JsonDictionaryContract etc)
if (contract is JsonArrayContract)
{
newContract = new JsonArrayContract(type);
}
//...
else
{
JsonObjectContract jsonObjectContract = contract as JsonObjectContract;
if (jsonObjectContract != null)
{
newContract = CloneJsonObjectContract(new JsonObjectContract(type), jsonObjectContract);
}
else
{
throw new ArgumentException("Unknown JsonContract type: " + contract.GetType() + ", object: " + contract);
}
}
//Copy properties like IsReference, OnSerializingCallbacks etc. and set the new converter
return newContract;
}
static JsonObjectContract CloneJsonObjectContract(JsonObjectContract newContract, JsonObjectContract oldContract)
{
newContract.OverrideCreator = oldContract.OverrideCreator;
newContract.DefaultCreator = oldContract.DefaultCreator;
newContract.DefaultCreatorNonPublic = oldContract.DefaultCreatorNonPublic;
newContract.ParametrizedConstructor = oldContract.ParametrizedConstructor; // If I do no copy this then the behavior of the old and new contract is different.
CloneJsonPropertyList(newContract.Properties, oldContract.Properties);
CloneJsonPropertyList(newContract.CreatorParameters, oldContract.CreatorParameters);
return newContract;
}
}
答案 0 :(得分:0)
可以从OverrideCreator
的参考来源看到两个属性ParametrizedConstructor
和JsonSerializerInternalReader.CreateNewObject()
(及其派生的委托属性ParameterizedCreator
)的精确函数:
如果有OverrideCreator
,请使用CreatorParameters
创建对象。
如果有DefaultCreator
并且它是公共的或私有的,JsonSerializer.ConstructorHandling
说要使用它,那么使用它来创建对象。
如果有ParameterizedCreator
,则使用它来创建对象。
否则无法构造对象,因此抛出异常。
因此,OverrideCreator
无条件优先,而ParameterizedCreator
仅在没有DefaultCreator
使用的情况下用作后备。我怀疑,Newtonsoft将后者标记为过时,因为他们希望将其转换为 internal
。即Json.NET的用户将始终能够设置无条件覆盖创建者,但不需要设置可能会或可能不会被调用的条件后备创建者,具体取决于价值ConstructorHandling
。
例如,如果要为特定类型T
注入创建方法,可以使用以下命令:
public class FactoryContractResolver<T> : DefaultContractResolver
{
readonly Func<T> creator;
public FactoryContractResolver(Func<T> creator)
{
this.creator = creator;
}
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
if (objectType == typeof(T))
{
contract.OverrideCreator = delegate(object[] args) { return creator(); };
if (contract.CreatorParameters != null)
contract.CreatorParameters.Clear();
}
return contract;
}
}
请注意,如果找不到构造函数,基类DefaultContractResolver.CreateObjectContract
将不会抛出异常。仅在反序列化期间实际尝试构造此类型的实例时抛出异常。