2
// http://code.google.com/p/servicestack/wiki/TypeSerializer
3
// ServiceStack.Text: .NET C# POCO Type Text Serializer.
6
// Demis Bellot (demis.bellot@gmail.com)
8
// Copyright 2011 Liquidbit Ltd.
10
// Licensed under the same terms of ServiceStack: new BSD license.
14
using System.Collections;
15
using System.Collections.Generic;
17
using System.Reflection;
18
using System.Threading;
19
using ServiceStack.Text.Json;
21
namespace ServiceStack.Text.Common
23
internal delegate void WriteMapDelegate(
26
WriteObjectDelegate writeKeyFn,
27
WriteObjectDelegate writeValueFn);
29
internal static class WriteDictionary<TSerializer>
30
where TSerializer : ITypeSerializer
32
private static readonly ITypeSerializer Serializer = JsWriter.GetTypeSerializer<TSerializer>();
36
internal Type KeyType;
37
internal Type ValueType;
39
public MapKey(Type keyType, Type valueType)
42
ValueType = valueType;
45
public bool Equals(MapKey other)
47
if (ReferenceEquals(null, other)) return false;
48
if (ReferenceEquals(this, other)) return true;
49
return Equals(other.KeyType, KeyType) && Equals(other.ValueType, ValueType);
52
public override bool Equals(object obj)
54
if (ReferenceEquals(null, obj)) return false;
55
if (ReferenceEquals(this, obj)) return true;
56
if (obj.GetType() != typeof(MapKey)) return false;
57
return Equals((MapKey)obj);
60
public override int GetHashCode()
64
return ((KeyType != null ? KeyType.GetHashCode() : 0) * 397) ^ (ValueType != null ? ValueType.GetHashCode() : 0);
69
static Dictionary<MapKey, WriteMapDelegate> CacheFns = new Dictionary<MapKey, WriteMapDelegate>();
71
public static Action<TextWriter, object, WriteObjectDelegate, WriteObjectDelegate>
72
GetWriteGenericDictionary(Type keyType, Type valueType)
74
WriteMapDelegate writeFn;
75
var mapKey = new MapKey(keyType, valueType);
76
if (CacheFns.TryGetValue(mapKey, out writeFn)) return writeFn.Invoke;
78
var genericType = typeof(ToStringDictionaryMethods<,,>).MakeGenericType(keyType, valueType, typeof(TSerializer));
79
var mi = genericType.GetMethod("WriteIDictionary", BindingFlags.Static | BindingFlags.Public);
80
writeFn = (WriteMapDelegate)Delegate.CreateDelegate(typeof(WriteMapDelegate), mi);
82
Dictionary<MapKey, WriteMapDelegate> snapshot, newCache;
86
newCache = new Dictionary<MapKey, WriteMapDelegate>(CacheFns);
87
newCache[mapKey] = writeFn;
89
} while (!ReferenceEquals(
90
Interlocked.CompareExchange(ref CacheFns, newCache, snapshot), snapshot));
92
return writeFn.Invoke;
95
public static void WriteIDictionary(TextWriter writer, object oMap)
97
WriteObjectDelegate writeKeyFn = null;
98
WriteObjectDelegate writeValueFn = null;
100
writer.Write(JsWriter.MapStartChar);
101
var encodeMapKey = false;
103
var map = (IDictionary)oMap;
105
foreach (var key in map.Keys)
107
var dictionaryValue = map[key];
109
var isNull = (dictionaryValue == null);
110
if (isNull && !JsConfig.IncludeNullValues) continue;
112
if (writeKeyFn == null)
114
var keyType = key.GetType();
115
writeKeyFn = Serializer.GetWriteFn(keyType);
116
encodeMapKey = Serializer.GetTypeInfo(keyType).EncodeMapKey;
119
if (writeValueFn == null)
120
writeValueFn = Serializer.GetWriteFn(dictionaryValue.GetType());
122
JsWriter.WriteItemSeperatorIfRanOnce(writer, ref ranOnce);
124
JsState.WritingKeyCount++;
125
JsState.IsWritingValue = false;
129
JsState.IsWritingValue = true; //prevent ""null""
130
writer.Write(JsWriter.QuoteChar);
131
writeKeyFn(writer, key);
132
writer.Write(JsWriter.QuoteChar);
136
writeKeyFn(writer, key);
139
JsState.WritingKeyCount--;
141
writer.Write(JsWriter.MapKeySeperator);
145
writer.Write(JsonUtils.Null);
149
JsState.IsWritingValue = true;
150
writeValueFn(writer, dictionaryValue);
151
JsState.IsWritingValue = false;
155
writer.Write(JsWriter.MapEndChar);
159
internal static class ToStringDictionaryMethods<TKey, TValue, TSerializer>
160
where TSerializer : ITypeSerializer
162
private static readonly ITypeSerializer Serializer = JsWriter.GetTypeSerializer<TSerializer>();
164
public static void WriteIDictionary(
167
WriteObjectDelegate writeKeyFn,
168
WriteObjectDelegate writeValueFn)
170
if (writer == null) return; //AOT
171
WriteGenericIDictionary(writer, (IDictionary<TKey, TValue>)oMap, writeKeyFn, writeValueFn);
174
public static void WriteGenericIDictionary(
176
IDictionary<TKey, TValue> map,
177
WriteObjectDelegate writeKeyFn,
178
WriteObjectDelegate writeValueFn)
182
writer.Write(JsonUtils.Null);
185
writer.Write(JsWriter.MapStartChar);
187
var encodeMapKey = Serializer.GetTypeInfo(typeof(TKey)).EncodeMapKey;
190
foreach (var kvp in map)
192
var isNull = (kvp.Value == null);
193
if (isNull && !JsConfig.IncludeNullValues) continue;
195
JsWriter.WriteItemSeperatorIfRanOnce(writer, ref ranOnce);
197
JsState.WritingKeyCount++;
198
JsState.IsWritingValue = false;
202
JsState.IsWritingValue = true; //prevent ""null""
203
writer.Write(JsWriter.QuoteChar);
204
writeKeyFn(writer, kvp.Key);
205
writer.Write(JsWriter.QuoteChar);
209
writeKeyFn(writer, kvp.Key);
212
JsState.WritingKeyCount--;
214
writer.Write(JsWriter.MapKeySeperator);
218
writer.Write(JsonUtils.Null);
222
JsState.IsWritingValue = true;
223
writeValueFn(writer, kvp.Value);
224
JsState.IsWritingValue = false;
228
writer.Write(JsWriter.MapEndChar);
b'\\ No newline at end of file'