JsonObjectContract.ParametrizedConstructor标记为已过时且无可选择

时间:2016-07-30 20:40:23

标签: json.net

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;
    } 
}

1 个答案:

答案 0 :(得分:0)

可以从OverrideCreator的参考来源看到两个属性ParametrizedConstructorJsonSerializerInternalReader.CreateNewObject()(及其派生的委托属性ParameterizedCreator)的精确函数:

  1. 如果有OverrideCreator,请使用CreatorParameters创建对象。

  2. 如果有DefaultCreator并且它是公共的或私有的,JsonSerializer.ConstructorHandling说要使用它,那么使用它来创建对象。

  3. 如果有ParameterizedCreator,则使用它来创建对象。

  4. 否则无法构造对象,因此抛出异常。

  5. 因此,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将不会抛出异常。仅在反序列化期间实际尝试构造此类型的实例时抛出异常。