即将推出本人原译的NewtonSoft.JSON官方手册中文版完整文档(.chm格式),敬请期待!
序列化教程
Json.NET序列化器可以序列化各种各样的.NET对象。此教程着眼于它如何工作,先讲高层次,后深入细节。
- 摘要
- 复合类型
- 基元类型
- 类型序列化的分解
摘要
在高层次,Json.NET序列化器将把基元.NET值转换为基元JSON值,将把.NET数组和集合转换为JSON数组,将把其它的一切转换为JSON对象。
在反序列化一个值时,如果Json.NET遭遇了不正确的JSON,它将抛出一个错误。例如,如果序列化器遭遇了一个JSON属性,带有一个值的数组,而且匹配.NET属性的类型不是一个集合,则将抛出一个错误,反之亦然。
复合类型
.NET | JSON |
---|---|
IList, IEnumerable, IList<T>, Array | Array (集合上的属性不能被序列化) |
IDictionary, IDictionary<TKey, TValue> | Object (只有字典名、值,不会序列化字典上的属性) |
Object (more detail below) | Object |
基元类型
.NET | JSON |
---|---|
String | String |
Byte SByte UInt16 Int16 UInt32 Int32 UInt64 Int64 | Integer |
Float Double Decimal | Float |
Enum | Integer (can be the enum value name with StringEnumConverter) |
DateTime | String (Serializing Dates in JSON) |
Byte[] | String (base 64 encoded) |
Type | String (type name) |
Guid | String |
TypeConverter (convertible to String) | String |
类型序列化的分解
此节内容包含了下面的小节:
- Objects
- IEnumerable, Lists, and Arrays
- Dictionaries and Hashtables
- Untyped Objects
- Dynamic
- ISerializable
- LINQ to JSON
- JsonConverter
Objects
不属于下面列出的任何其他类别的.NET类型(即不是列表、字典、动态、实现ISerializable等)将被序列化为JSON对象。你还可以通过把JsonObjectAttribute放到类型上来强迫一个类型被序列化为JSON。
默认情况下,一个类型的属性会在opt-out模式下被序列化。这意味着,所有带有getter的公共字段和属性都会自动序列化为JSON,而不应该序列化的字段和属性则会通过在其上放置JsonIgnoreAttribute来进行选择。若要序列化私有成员,可以在私有字段和属性上放置JsonPropertyAttribute。
也可以使用opt-in模式来序列化类型。只有具有JsonPropertyAttribute或DataMemberAttribute的属性或字段将被序列化。对象的Opt-in模式是通过在类型上放置JsonObjectAttribute或DataContractAttribute来指定的。
最后,可以使用字段模式来序列化炻工。所有的字段,无论是公开的还是私有的,都被序列化,所有属性都被忽略。这可以通过利用JsonObjectAttribute在类型上设置MemberSerialization.Fields
来指定,或者使用.NET SerializableAttribute并在DefaultContractResolver上把IgnoreSerializableAttribute设置为false来指定。
IEnumerable, Lists, and Arrays
.NET列表(类型继承自IEnumerable)以及.NET数组会被转换为JSON数组。因为JSON数组只支持值的范围,而不支持属性,所有声明在.NET集合上的任何额外的属性和字段都不会被序列化。在某些情形中,类型实例化了IEnumerable,但是不想要JSON数组,则可以在类型上放置JsonObjectAttribute,以迫使它被序列化为一个JSON对象。
JsonArrayAttribute上面有选项,用来自定义应用到集合项上的JsonConverter、类型名称处理和引用处理。
请注意,如果在序列化器上已经针对JSON数组启用了TypeNameHandling或PreserveReferencesHandling,则JSON数组将被包装入一个容纳对象。此对象将具有类型名称、引用属性以及一个$value属性,它具有集合的数据。
在序列化时,如果某个成员被类型化为接口 IList<T>,则它将被反序列化为List<T>。
你可以在此处进一步了解序列化集合:序列化集合
字典和哈希表
.NET字典(继承自IDictionary的类型)被转换为JSON对象。请注意,在序列化时,只有字典名称、值会被写到JSON对象中,在反序列化时,JSON对象上的属性将被添加到字典的名称值上。在序列化时,.NET字典上的额外的成员会被忽略。
当序列化一个字典时,字典的键被转换为字符串,用作JSON对象属性名称。可以自定义写作键的字符串,既可以通过针对键类型重写ToString(),也可以通过TypeConverter来实现。TypeConverter也支持在反序列化一个字典时,把自定义的字符串转换回去。
JsonDictionaryAttribute上面有选项,用来自定义应用到集合项上的JsonConverter,类型名称处理以及引用处理。
在反序列化时,如果一个成员被类型化为接口IDictionary<TKey, TValue>,则它将被反序列化为Dictionary<TKey, TValue>。
你可以在此处进一步了解序列化集合:序列化集合
未类型化的对象
在类上的.NET属性,如果没有指定类型(亦即,它们只是对象)也会如常序列化。当未类型化的属性被反序列化时,序列化器没有办法知道要创建哪种类型(除非启用了类型名称处理,而且JSON包含了类型名称)。
对于那些未类型化的属性,Json.NET序列化器将JSON读入LINQ to JSON对象,并把它们设置为属性。将针对JSON对象创建JObject;将针对JSON数组创建JArray,针针对基元JSON值创建JValue。
动态
.NET中有两种不同的动态用法(在.NET 4中引入)。第一种是.NET属性,带有动态的类型。动态属性行为像属性,被声明为对象:可以给它分配一些值,但是区别是可以在动态的属性上调用属性和方法,无需强制转换。在Json.NET中,动态属性被序列化、反序列化,与非类型化的对象完全一致:因为动态不是实际的类型,Json.NET会回退到将Json反序列化为LINQ to Json对象。
在.NET中动态的第二种用法是由实现 IDynamicMetaObjectProvider的类型来实现的。此接口让实现器创建动态对象,截断在一个对象上调用的属性和方法,并使用它们。ExpandoObject是动态对象的好例子。
动态对象会被序列化为JSON对象。针对DynamicMetaObject.GetDynamicMemberNames()返回的所有成员编写属性。动态对象的常规属性默认不会被序列化,但是可以被包含,只要在它上面放JsonPropertyAttribute。
在反序列化动态对象时,序列化器首先尝试在名称匹配的常规.NET成员上设置JSON属性值。如果找不到带有那个名称的.NET成员,则序列化器将在动态对象上调用SetMember。因为动态对象上的动态成员不存在类型信息,所以分配给他们的值将是LINQ to JSON对象。
ISerializable
实现ISerializable的类型,以及带有SerializableAttribute标记的类型会被序列化为JSON对象。在序列化时,只用到了返回自ISerializable.GetObjectData的值;类型上的成员会被忽略。在反序列化时,调用了带有SerializationInfo和StreamingContext的构造器,传递JSON对象的值。
在一些不需要这种行为的情形中,可在.NET类型上面放置JsonObjectAttribute,实现Iserializable强制它被序列化为一个常规JSON对象。
LINQ to JSON
当Json.NET序列化器遭遇到了LINQ to JSON类型时,LINQ to JSON类型(例如,JObject和JArray)会自动序列化和反序列化为和它们等价的JSON。
JsonConverter
JsonConvert完全重写了可被JsonConverter转换的值(亦即,对于那种类型,CanConvert返回true)的序列化。检查JsonSerializer是否可以转换值的测试优先于所有其他测试。
可以在很多地方定义并指定JsonConverters:在某个成员的某个特性上、在一个类的特性上,或者添加到JsonSerializer的转换器集合上。使用哪种JsonConvert的优先顺序,首先一个成员的特定上定义的JsonConverter,然后是一个类上定义的JsonConverter,最后是传给JsonSerializer的任何转换器。
Note: |
---|
因为JsonConverter创建了一个新值,所以转换器不能与只读属性配合作用,因为没办法给这样的属性赋新值。请将属性更改为具有公共setter,或在属性上放置JsonPropertyAttribute或DataMemberAttribute。 |