我试图了解如何JsonConvert.DeserializeObject<X>(someJsonString)使用构造函数设置值.
using Newtonsoft.json
public class X {
[JsonProperty("some_Property")]
public string SomeProperty {get;}
[JsonProperty("some_Property_2")]
public string SomeProperty2 {get;}
public X(string someProperty, string someProperty2) {
SomeProperty = someProperty;
SomeProperty2 = someProperty2;
}
public static X parseObject(string parseThisJson) {
JsonConvert.DeserializeObject<X>(someJsonString);
}
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,我想了解JsonConvert.DeserializeObject如何能够正确地反序列化它.json序列化是否使用此public X(string someProperty, string someProperty2)构造函数?如果是这样,如何调用和使用此构造函数?
会发生什么是parseThisJson除了some_Property和some_Property_2之外还有更多的键值对?
Ser*_*kiy 18
在深入了解Newtonsoft.Json源代码后,我可以告诉你在那里使用的对象实例化算法.是的,构造函数几乎总是被调用(*).问题只是"哪一个?".这是答案的彩色版本:
TL; DR首先,Newtonsoft.Json创建JsonContract了要反序列化的类型.它的抽象类.它有不同的字典,数组,对象等实现.在你的情况下JsonObjectContract将创建.合同包含有关反序列化类型的各种元数据.对我们来说最有趣的是:
IsInstantiable - 定义反序列化类型是否可实例化(见下文)Properties - 它的对象属性集合DefaultCreator - 用于创建对象的默认创建方法 Func<object>DefaultCreatorNonPublic - 定义默认构造函数是否为非公共构造函数OverrideCreator- 非默认创建者,如果JsonConstructorAttribute应用于对象的构造函数则使用ParametrizedCreator - 调用paramterized构造函数的创建者,如果我们既没有默认也没有覆盖创建者,则使用它CreatorParameters - 用于覆盖创建者或参数化创建者的属性集合MemberSerialization - 此值定义属性和字段的序列化方式.默认情况下,它设置为OptOut- 即所有公共成员都被序列化.如果要排除某些内容,则应使用JsonIgnore属性.但也有Fields选项,即所有公共和私人领域都应该序列化.有几个可以打开此选项.但默认情况下它是禁用的.可以通过反映类型metdata来检索这些元数据中的一些.例如IsInstantiable,通过检查反序列化类型是否不是抽象而不是接口来计算.添加了一些元数据DefaultContractResolver.特别是,它定义了如何构造对象的方式.在伪代码中:
if (contract.IsInstantiable)
{
if (type has default constructor or its a value type)
{
contract.DefaultCreator = get default (parameterless) constructor;
contract.DefaultCreatorNonPublic = check if default constructor public
}
if (we have constructor marked with JsonConstructorAttribute)
{
contract.OverrideCreator = constructor marked with attribute
contract.CreatorParameters = get properties which match constructor parameters
}
else if (contract.MemberSerialization == MemberSerialization.Fields)
{
// only if the upplication if fully trusted
contract.DefaultCreator = FormatterServices.GetUninitializedObject
}
else if (contract.DefaultCreator == null || contract.DefaultCreatorNonPublic)
{
if (we have one public constructor with parameters)
{
contract.ParametrizedCreator = constructor with parameters;
contract.CreatorParameters = get properties which match ctor parameters
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以,正如你可以看到prioirty转到标有JsonConstructorAttribute属性的构造函数.如果有多个这样的构造函数,您也会收到错误.
(*)接下来是唯一一种可以在不调用构造函数的情况下创建对象的情况.例如,如果您将使用[JsonObject(MemberSerialization = MemberSerialization.Fields)]属性标记类来序列化私有字段.
然后我们检查我们是否有默认的无参数构造函数,它不是私有的.如果是这样,那么我们去寻找其他构造函数 - 一个具有参数且应该是公共的构造函数.如果有多个这样的构造函数,您也会收到错误.
最后要注意的是 - CraeatorParameters.Newtonsoft.Json使用反射来获取构造函数参数,然后尝试通过这些构造函数参数的名称找到与对象属性最接近的匹配.它还检查要匹配的属性和参数的类型.如果找不到匹配项,则默认值将传递给此参数化构造函数.