Json.Net - Custom Converter

Json.Net 用到後面,我們免不了有時會要 Custom Converter 去做序列化的客製動作。


使用 Json.Net 要做自定義序列化,我們可以 Custom Json.Net 的 Converter,為此需要建立一個 Converter 類別,將之繼承自 JsonConverter,接著將繼承而來的方法實作即可。


CanConverter 用來決定該型別是否可被該 Converter 處理、WriteJson 用來序列化物件、ReadJson 用來解序列化物件。


像是我們可以像下面這樣做個簡易的 Converter,裡面只是單純的將物件序列化與解序列化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System;
using Newtonsoft.Json;

namespace LevelUp.Converter
{
public class ConcreteTypeConverter<TConcrete> : JsonConverter
{
public override bool CanConvert( Type objectType)
{
return true ;
}

public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return serializer.Deserialize<TConcrete>(reader);
}

public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
}
}


當我們在序列化物件時,若物件的成員屬性是 Interface,就可以用來指定序列化與解序列化時實際所要用的型態。

1
2
[JsonConverter(typeof(ConcreteTypeConverter<DecisionNode[]>))]
IDecisionNode[] Nodes { get ; }


或者是像下面這段用來處理 Dictionary 的序列話與解序列化的 Converter 程式,裡面會用 JsonWriter 去處理序列化的動作、用 JsonReader 去處理解序列化的動作,寫起來比較複雜些,但可進行比較進階的處理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json;

namespace LevelUp.Converter
{
public class DictionaryConverter<TKey, TValue> : JsonConverter
{
#region Methods
private static bool TypeImplementsGenericInterface( Type concreteType, Type interfaceType)
{
return concreteType.GetInterfaces()
.Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == interfaceType);
}
public override bool CanConvert( Type objectType)
{
return (typeof (IDictionary).IsAssignableFrom(objectType) ||
TypeImplementsGenericInterface(objectType, typeof(IDictionary <,>)));
}

public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.None) return null ;

var dict = new Dictionary<TKey, TValue>();

reader.Read();

while (reader.TokenType == JsonToken.StartArray)
{
reader.Read();

var key = serializer.Deserialize<TKey>(reader);

reader.Read();
var value = serializer.Deserialize<TValue>(reader);

reader.Read();
reader.Read();

dict.Add(key, value);
}

return dict;
}

public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer)
{
var dict = value as IDictionary;
var keys = dict.Keys;
var values = dict.Values;
var valueEnumerator = values.GetEnumerator();

writer.WriteStartArray();
foreach (var key in keys)
{
valueEnumerator.MoveNext();

writer.WriteStartArray();
serializer.Serialize(writer, key);
serializer.Serialize(writer, valueEnumerator.Current);
writer.WriteEndArray();
}
writer.WriteEndArray();
}
#endregion Methods
}
}