C#中的JSON反序列化如何工作 [英] How does JSON deserialization in C# work
问题描述
我试图了解JsonConvert.DeserializeObject<X>(someJsonString)
如何通过使用构造函数来设置值.
I am trying to understand how JsonConvert.DeserializeObject<X>(someJsonString)
is able to set the values by using the constructor.
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);
}
}
在上面的代码中,我想了解JsonConvert.DeserializeObject如何能够正确地反序列化它.
json序列化是否使用此public X(string someProperty, string someProperty2)
构造函数?如果是这样,该构造函数如何调用和使用?
In above code I want to understand how is JsonConvert.DeserializeObject is able to deserialize it correctly.
Does the json serialize uses this public X(string someProperty, string someProperty2)
constructor? If so how is this constructor called and used?
parseThisJson会发生什么,除了some_Property和some_Property_2还有更多的键值对?
What will happen is parseThisJson have more key value pairs in addition to some_Property and some_Property_2?
推荐答案
深入研究 Newtonsoft.Json 我可以告诉您那里使用的对象实例化算法.是的,构造函数几乎总是被称为(*).问题只是哪个?".这是答案的彩色版本:
After digging into Newtonsoft.Json sources I can tell you algorithm of object instantiation which is used there. And yes, constructor is almost always called (*). The question is only "which one?". Here is colorful version of answer:
TL;DR First of all, Newtonsoft.Json creates JsonContract
of the type which you are going to deserialize. Its abstract class. And it has different implementations for dictionaries, arrays, objects etc. In your case JsonObjectContract
will be created. Contract contains various metadata about deserialized type. Most interesting for us are:
-
IsInstantiable
-定义反序列化类型是否可实例化(请参见下文) -
Properties
-它的对象属性集合 -
DefaultCreator
-用于创建对象Func<object>
的默认创建方法
-
DefaultCreatorNonPublic
-定义默认构造函数是否不公开 -
OverrideCreator
-非默认创建者,如果将JsonConstructorAttribute
应用于对象的构造函数,则使用 -
ParametrizedCreator
-调用参数化构造函数的创建者,如果我们既没有默认创建者又没有覆盖创建者,则使用它 -
CreatorParameters
-用于覆盖创建者或参数化创建者的属性的集合 -
MemberSerialization
-此值定义了属性和字段被序列化.默认情况下,它设置为OptOut
-即所有公共成员都已序列化.如果要排除某些内容,则应使用JsonIgnore
属性.但是还有Fields
选项,该选项表示所有公共和private 字段均应序列化.有几个可以启用此选项.但是默认情况下,它是禁用的.
IsInstantiable
- defines whether deserialized type is instantiable (see below)Properties
- its collection of object propertiesDefaultCreator
- default creation method used to create objectFunc<object>
DefaultCreatorNonPublic
- defines whether default constructor is non publicOverrideCreator
- non-default creator, used ifJsonConstructorAttribute
is applied to object's constructorParametrizedCreator
- creator which calls paramterized constructor, it is used if we don't have neither default nor override creatorsCreatorParameters
- collection of properties which are used for override creator or parametrized creatorMemberSerialization
- this value defines the way how properties and fields are serialized. By default it is set toOptOut
- i.e. all public members are serialized. If you want to exclude some, you should useJsonIgnore
attribute. But there is alsoFields
option, which says that all public and private fields should be serialized. There is several to turn-on this option. But by default its disabled.
可以通过反映类型metdata来检索其中一些元数据.例如.通过检查反序列化类型是否不是抽象和非接口来计算IsInstantiable
. DefaultContractResolver
.特别是,它定义了应如何构造对象的方式.用伪代码:
Some of this metadata can be retrieved by reflecting type metdata. E.g. IsInstantiable
is calculated by checking whether deserialized type is not abstract and not interface. Some metadata are added by DefaultContractResolver
. In particular, it defines the way how object should be constructed. In pseudo-code:
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
}
}
}
因此,如您所见,优先级标记为带有JsonConstructorAttribute
属性的构造函数.如果有多个这样的构造函数,您也会收到错误消息.
So, as you can see prioirty goes to constructor marked with JsonConstructorAttribute
attribute. You will also get error if there is more than one such constructor.
(*)接下来是唯一一种无需调用构造函数即可创建对象的情况.例如.如果您要使用[JsonObject(MemberSerialization = MemberSerialization.Fields)]
属性标记类以序列化私有字段.
(*) Next goes the only case when object can be created without calling constructor. E.g. if you'll mark class with [JsonObject(MemberSerialization = MemberSerialization.Fields)]
attribute to serialize private fields.
然后我们检查是否有默认的无参数构造函数,该构造函数不是私有的.如果是这样,那么我们去寻找其他构造函数-一个具有参数并且应该是公共的.如果这样的构造函数不止一个,则也会出错.
Then we check if we have default parameterless constructor which is not private. If so, then we go for other constructor - one which has parameters and should be public. If there is more than one such constructor, you will also get error.
最后要注意的是-CraeatorParameters
. Newtonsoft.Json使用反射来获取构造函数参数,然后尝试通过这些构造函数参数的名称查找与对象属性最接近的匹配项.它还检查属性的类型和参数是否匹配.如果找不到匹配项,则默认值将传递给该参数化的构造函数.
And last thing to note - CraeatorParameters
. Newtonsoft.Json uses reflection to get constructor parameters and then tries to find closest match by name of these constructor parameters to object's properties. It also checks type of property and parameters to match. If there is no match found, then default value will be passed to this parametrized constructor.
这篇关于C#中的JSON反序列化如何工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!