corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 #region Header
2 /*
3 * JsonMapper.cs
4 * JSON to .Net object and object to JSON conversions.
5 *
6 * The authors disclaim copyright to this source code. For more details, see
7 * the COPYING file included with this distribution.
8 */
9 #endregion
10  
11  
12 using System;
13 using System.Collections;
14 using System.Collections.Generic;
15 using System.Globalization;
16 using System.IO;
17 using System.Reflection;
18  
19  
20 namespace LitJson
21 {
22 internal struct PropertyMetadata
23 {
24 public MemberInfo Info;
25 public bool IsField;
26 public Type Type;
27 }
28  
29  
30 internal struct ArrayMetadata
31 {
32 private Type element_type;
33 private bool is_array;
34 private bool is_list;
35  
36  
37 public Type ElementType {
38 get {
39 if (element_type == null)
40 return typeof (JsonData);
41  
42 return element_type;
43 }
44  
45 set { element_type = value; }
46 }
47  
48 public bool IsArray {
49 get { return is_array; }
50 set { is_array = value; }
51 }
52  
53 public bool IsList {
54 get { return is_list; }
55 set { is_list = value; }
56 }
57 }
58  
59  
60 internal struct ObjectMetadata
61 {
62 private Type element_type;
63 private bool is_dictionary;
64  
65 private IDictionary<string, PropertyMetadata> properties;
66  
67  
68 public Type ElementType {
69 get {
70 if (element_type == null)
71 return typeof (JsonData);
72  
73 return element_type;
74 }
75  
76 set { element_type = value; }
77 }
78  
79 public bool IsDictionary {
80 get { return is_dictionary; }
81 set { is_dictionary = value; }
82 }
83  
84 public IDictionary<string, PropertyMetadata> Properties {
85 get { return properties; }
86 set { properties = value; }
87 }
88 }
89  
90  
91 internal delegate void ExporterFunc (object obj, JsonWriter writer);
92 public delegate void ExporterFunc<T> (T obj, JsonWriter writer);
93  
94 internal delegate object ImporterFunc (object input);
95 public delegate TValue ImporterFunc<TJson, TValue> (TJson input);
96  
97 public delegate IJsonWrapper WrapperFactory ();
98  
99  
100 public class JsonMapper
101 {
102 #region Fields
103 private static int max_nesting_depth;
104  
105 private static IFormatProvider datetime_format;
106  
107 private static IDictionary<Type, ExporterFunc> base_exporters_table;
108 private static IDictionary<Type, ExporterFunc> custom_exporters_table;
109  
110 private static IDictionary<Type,
111 IDictionary<Type, ImporterFunc>> base_importers_table;
112 private static IDictionary<Type,
113 IDictionary<Type, ImporterFunc>> custom_importers_table;
114  
115 private static IDictionary<Type, ArrayMetadata> array_metadata;
116 private static readonly object array_metadata_lock = new Object ();
117  
118 private static IDictionary<Type,
119 IDictionary<Type, MethodInfo>> conv_ops;
120 private static readonly object conv_ops_lock = new Object ();
121  
122 private static IDictionary<Type, ObjectMetadata> object_metadata;
123 private static readonly object object_metadata_lock = new Object ();
124  
125 private static IDictionary<Type,
126 IList<PropertyMetadata>> type_properties;
127 private static readonly object type_properties_lock = new Object ();
128  
129 private static JsonWriter static_writer;
130 private static readonly object static_writer_lock = new Object ();
131 #endregion
132  
133  
134 #region Constructors
135 static JsonMapper ()
136 {
137 max_nesting_depth = 100;
138  
139 array_metadata = new Dictionary<Type, ArrayMetadata> ();
140 conv_ops = new Dictionary<Type, IDictionary<Type, MethodInfo>> ();
141 object_metadata = new Dictionary<Type, ObjectMetadata> ();
142 type_properties = new Dictionary<Type,
143 IList<PropertyMetadata>> ();
144  
145 static_writer = new JsonWriter ();
146  
147 datetime_format = DateTimeFormatInfo.InvariantInfo;
148  
149 base_exporters_table = new Dictionary<Type, ExporterFunc> ();
150 custom_exporters_table = new Dictionary<Type, ExporterFunc> ();
151  
152 base_importers_table = new Dictionary<Type,
153 IDictionary<Type, ImporterFunc>> ();
154 custom_importers_table = new Dictionary<Type,
155 IDictionary<Type, ImporterFunc>> ();
156  
157 RegisterBaseExporters ();
158 RegisterBaseImporters ();
159 }
160 #endregion
161  
162  
163 #region Private Methods
164 private static void AddArrayMetadata (Type type)
165 {
166 if (array_metadata.ContainsKey (type))
167 return;
168  
169 ArrayMetadata data = new ArrayMetadata ();
170  
171 data.IsArray = type.IsArray;
172  
173 if (type.GetInterface ("System.Collections.IList") != null)
174 data.IsList = true;
175  
176 foreach (PropertyInfo p_info in type.GetProperties ()) {
177 if (p_info.Name != "Item")
178 continue;
179  
180 ParameterInfo[] parameters = p_info.GetIndexParameters ();
181  
182 if (parameters.Length != 1)
183 continue;
184  
185 if (parameters[0].ParameterType == typeof (int))
186 data.ElementType = p_info.PropertyType;
187 }
188  
189 lock (array_metadata_lock) {
190 try {
191 array_metadata.Add (type, data);
192 } catch (ArgumentException) {
193 return;
194 }
195 }
196 }
197  
198 private static void AddObjectMetadata (Type type)
199 {
200 if (object_metadata.ContainsKey (type))
201 return;
202  
203 ObjectMetadata data = new ObjectMetadata ();
204  
205 if (type.GetInterface ("System.Collections.IDictionary") != null)
206 data.IsDictionary = true;
207  
208 data.Properties = new Dictionary<string, PropertyMetadata> ();
209  
210 foreach (PropertyInfo p_info in type.GetProperties ()) {
211 if (p_info.Name == "Item") {
212 ParameterInfo[] parameters = p_info.GetIndexParameters ();
213  
214 if (parameters.Length != 1)
215 continue;
216  
217 if (parameters[0].ParameterType == typeof (string))
218 data.ElementType = p_info.PropertyType;
219  
220 continue;
221 }
222  
223 PropertyMetadata p_data = new PropertyMetadata ();
224 p_data.Info = p_info;
225 p_data.Type = p_info.PropertyType;
226  
227 data.Properties.Add (p_info.Name, p_data);
228 }
229  
230 foreach (FieldInfo f_info in type.GetFields ()) {
231 PropertyMetadata p_data = new PropertyMetadata ();
232 p_data.Info = f_info;
233 p_data.IsField = true;
234 p_data.Type = f_info.FieldType;
235  
236 data.Properties.Add (f_info.Name, p_data);
237 }
238  
239 lock (object_metadata_lock) {
240 try {
241 object_metadata.Add (type, data);
242 } catch (ArgumentException) {
243 return;
244 }
245 }
246 }
247  
248 private static void AddTypeProperties (Type type)
249 {
250 if (type_properties.ContainsKey (type))
251 return;
252  
253 IList<PropertyMetadata> props = new List<PropertyMetadata> ();
254  
255 foreach (PropertyInfo p_info in type.GetProperties ()) {
256 if (p_info.Name == "Item")
257 continue;
258  
259 PropertyMetadata p_data = new PropertyMetadata ();
260 p_data.Info = p_info;
261 p_data.IsField = false;
262 props.Add (p_data);
263 }
264  
265 foreach (FieldInfo f_info in type.GetFields ()) {
266 PropertyMetadata p_data = new PropertyMetadata ();
267 p_data.Info = f_info;
268 p_data.IsField = true;
269  
270 props.Add (p_data);
271 }
272  
273 lock (type_properties_lock) {
274 try {
275 type_properties.Add (type, props);
276 } catch (ArgumentException) {
277 return;
278 }
279 }
280 }
281  
282 private static MethodInfo GetConvOp (Type t1, Type t2)
283 {
284 lock (conv_ops_lock) {
285 if (! conv_ops.ContainsKey (t1))
286 conv_ops.Add (t1, new Dictionary<Type, MethodInfo> ());
287 }
288  
289 if (conv_ops[t1].ContainsKey (t2))
290 return conv_ops[t1][t2];
291  
292 MethodInfo op = t1.GetMethod (
293 "op_Implicit", new Type[] { t2 });
294  
295 lock (conv_ops_lock) {
296 try {
297 conv_ops[t1].Add (t2, op);
298 } catch (ArgumentException) {
299 return conv_ops[t1][t2];
300 }
301 }
302  
303 return op;
304 }
305  
306 private static object ReadValue (Type inst_type, JsonReader reader)
307 {
308 reader.Read ();
309  
310 if (reader.Token == JsonToken.ArrayEnd)
311 return null;
312  
313 if (reader.Token == JsonToken.Null) {
314  
315 if (! inst_type.IsClass)
316 throw new JsonException (String.Format (
317 "Can't assign null to an instance of type {0}",
318 inst_type));
319  
320 return null;
321 }
322  
323 if (reader.Token == JsonToken.Double ||
324 reader.Token == JsonToken.Int ||
325 reader.Token == JsonToken.Long ||
326 reader.Token == JsonToken.String ||
327 reader.Token == JsonToken.Boolean) {
328  
329 Type json_type = reader.Value.GetType ();
330  
331 if (inst_type.IsAssignableFrom (json_type))
332 return reader.Value;
333  
334 // If there's a custom importer that fits, use it
335 if (custom_importers_table.ContainsKey (json_type) &&
336 custom_importers_table[json_type].ContainsKey (
337 inst_type)) {
338  
339 ImporterFunc importer =
340 custom_importers_table[json_type][inst_type];
341  
342 return importer (reader.Value);
343 }
344  
345 // Maybe there's a base importer that works
346 if (base_importers_table.ContainsKey (json_type) &&
347 base_importers_table[json_type].ContainsKey (
348 inst_type)) {
349  
350 ImporterFunc importer =
351 base_importers_table[json_type][inst_type];
352  
353 return importer (reader.Value);
354 }
355  
356 // Maybe it's an enum
357 if (inst_type.IsEnum)
358 return Enum.ToObject (inst_type, reader.Value);
359  
360 // Try using an implicit conversion operator
361 MethodInfo conv_op = GetConvOp (inst_type, json_type);
362  
363 if (conv_op != null)
364 return conv_op.Invoke (null,
365 new object[] { reader.Value });
366  
367 // No luck
368 throw new JsonException (String.Format (
369 "Can't assign value '{0}' (type {1}) to type {2}",
370 reader.Value, json_type, inst_type));
371 }
372  
373 object instance = null;
374  
375 if (reader.Token == JsonToken.ArrayStart) {
376  
377 AddArrayMetadata (inst_type);
378 ArrayMetadata t_data = array_metadata[inst_type];
379  
380 if (! t_data.IsArray && ! t_data.IsList)
381 throw new JsonException (String.Format (
382 "Type {0} can't act as an array",
383 inst_type));
384  
385 IList list;
386 Type elem_type;
387  
388 if (! t_data.IsArray) {
389 list = (IList) Activator.CreateInstance (inst_type);
390 elem_type = t_data.ElementType;
391 } else {
392 list = new ArrayList ();
393 elem_type = inst_type.GetElementType ();
394 }
395  
396 while (true) {
397 object item = ReadValue (elem_type, reader);
398 if (reader.Token == JsonToken.ArrayEnd)
399 break;
400  
401 list.Add (item);
402 }
403  
404 if (t_data.IsArray) {
405 int n = list.Count;
406 instance = Array.CreateInstance (elem_type, n);
407  
408 for (int i = 0; i < n; i++)
409 ((Array) instance).SetValue (list[i], i);
410 } else
411 instance = list;
412  
413 } else if (reader.Token == JsonToken.ObjectStart) {
414  
415 AddObjectMetadata (inst_type);
416 ObjectMetadata t_data = object_metadata[inst_type];
417  
418 instance = Activator.CreateInstance (inst_type);
419  
420 while (true) {
421 reader.Read ();
422  
423 if (reader.Token == JsonToken.ObjectEnd)
424 break;
425  
426 string property = (string) reader.Value;
427  
428 if (t_data.Properties.ContainsKey (property)) {
429 PropertyMetadata prop_data =
430 t_data.Properties[property];
431  
432 if (prop_data.IsField) {
433 ((FieldInfo) prop_data.Info).SetValue (
434 instance, ReadValue (prop_data.Type, reader));
435 } else {
436 PropertyInfo p_info =
437 (PropertyInfo) prop_data.Info;
438  
439 if (p_info.CanWrite)
440 p_info.SetValue (
441 instance,
442 ReadValue (prop_data.Type, reader),
443 null);
444 else
445 ReadValue (prop_data.Type, reader);
446 }
447  
448 } else {
449 if (! t_data.IsDictionary)
450 throw new JsonException (String.Format (
451 "The type {0} doesn't have the " +
452 "property '{1}'", inst_type, property));
453  
454 ((IDictionary) instance).Add (
455 property, ReadValue (
456 t_data.ElementType, reader));
457 }
458  
459 }
460  
461 }
462  
463 return instance;
464 }
465  
466 private static IJsonWrapper ReadValue (WrapperFactory factory,
467 JsonReader reader)
468 {
469 reader.Read ();
470  
471 if (reader.Token == JsonToken.ArrayEnd ||
472 reader.Token == JsonToken.Null)
473 return null;
474  
475 IJsonWrapper instance = factory ();
476  
477 switch (reader.Token)
478 {
479 case JsonToken.String:
480 instance.SetString ((string) reader.Value);
481 break;
482 case JsonToken.Double:
483 instance.SetDouble ((double) reader.Value);
484 break;
485 case JsonToken.Int:
486 instance.SetInt ((int) reader.Value);
487 break;
488 case JsonToken.Long:
489 instance.SetLong ((long) reader.Value);
490 break;
491 case JsonToken.Boolean:
492 instance.SetBoolean ((bool) reader.Value);
493 break;
494 case JsonToken.ArrayStart:
495 instance.SetJsonType (JsonType.Array);
496  
497 while (true) {
498 IJsonWrapper item = ReadValue (factory, reader);
499 if (item == null && reader.Token == JsonToken.ArrayEnd)
500 break;
501  
502 ((IList) instance).Add (item);
503 }
504 break;
505 case JsonToken.ObjectStart:
506 instance.SetJsonType (JsonType.Object);
507  
508 while (true) {
509 reader.Read ();
510 if (reader.Token == JsonToken.ObjectEnd)
511 break;
512  
513 string property = (string) reader.Value;
514 ((IDictionary) instance)[property] = ReadValue (
515 factory, reader);
516 }
517 break;
518 }
519  
520 return instance;
521 }
522  
523 private static void RegisterBaseExporters ()
524 {
525 base_exporters_table[typeof (byte)] =
526 delegate (object obj, JsonWriter writer) {
527 writer.Write (Convert.ToInt32 ((byte) obj));
528 };
529  
530 base_exporters_table[typeof (char)] =
531 delegate (object obj, JsonWriter writer) {
532 writer.Write (Convert.ToString ((char) obj));
533 };
534  
535 base_exporters_table[typeof (DateTime)] =
536 delegate (object obj, JsonWriter writer) {
537 writer.Write (Convert.ToString ((DateTime) obj,
538 datetime_format));
539 };
540  
541 base_exporters_table[typeof (decimal)] =
542 delegate (object obj, JsonWriter writer) {
543 writer.Write ((decimal) obj);
544 };
545  
546 base_exporters_table[typeof (sbyte)] =
547 delegate (object obj, JsonWriter writer) {
548 writer.Write (Convert.ToInt32 ((sbyte) obj));
549 };
550  
551 base_exporters_table[typeof (short)] =
552 delegate (object obj, JsonWriter writer) {
553 writer.Write (Convert.ToInt32 ((short) obj));
554 };
555  
556 base_exporters_table[typeof (ushort)] =
557 delegate (object obj, JsonWriter writer) {
558 writer.Write (Convert.ToInt32 ((ushort) obj));
559 };
560  
561 base_exporters_table[typeof (uint)] =
562 delegate (object obj, JsonWriter writer) {
563 writer.Write (Convert.ToUInt64 ((uint) obj));
564 };
565  
566 base_exporters_table[typeof (ulong)] =
567 delegate (object obj, JsonWriter writer) {
568 writer.Write ((ulong) obj);
569 };
570 }
571  
572 private static void RegisterBaseImporters ()
573 {
574 ImporterFunc importer;
575  
576 importer = delegate (object input) {
577 return Convert.ToByte ((int) input);
578 };
579 RegisterImporter (base_importers_table, typeof (int),
580 typeof (byte), importer);
581  
582 importer = delegate (object input) {
583 return Convert.ToUInt64 ((int) input);
584 };
585 RegisterImporter (base_importers_table, typeof (int),
586 typeof (ulong), importer);
587  
588 importer = delegate (object input) {
589 return Convert.ToSByte ((int) input);
590 };
591 RegisterImporter (base_importers_table, typeof (int),
592 typeof (sbyte), importer);
593  
594 importer = delegate (object input) {
595 return Convert.ToInt16 ((int) input);
596 };
597 RegisterImporter (base_importers_table, typeof (int),
598 typeof (short), importer);
599  
600 importer = delegate (object input) {
601 return Convert.ToUInt16 ((int) input);
602 };
603 RegisterImporter (base_importers_table, typeof (int),
604 typeof (ushort), importer);
605  
606 importer = delegate (object input) {
607 return Convert.ToUInt32 ((int) input);
608 };
609 RegisterImporter (base_importers_table, typeof (int),
610 typeof (uint), importer);
611  
612 importer = delegate (object input) {
613 return Convert.ToSingle ((int) input);
614 };
615 RegisterImporter (base_importers_table, typeof (int),
616 typeof (float), importer);
617  
618 importer = delegate (object input) {
619 return Convert.ToDouble ((int) input);
620 };
621 RegisterImporter (base_importers_table, typeof (int),
622 typeof (double), importer);
623  
624 importer = delegate (object input) {
625 return Convert.ToDecimal ((double) input);
626 };
627 RegisterImporter (base_importers_table, typeof (double),
628 typeof (decimal), importer);
629  
630  
631 importer = delegate (object input) {
632 return Convert.ToUInt32 ((long) input);
633 };
634 RegisterImporter (base_importers_table, typeof (long),
635 typeof (uint), importer);
636  
637 importer = delegate (object input) {
638 return Convert.ToChar ((string) input);
639 };
640 RegisterImporter (base_importers_table, typeof (string),
641 typeof (char), importer);
642  
643 importer = delegate (object input) {
644 return Convert.ToDateTime ((string) input, datetime_format);
645 };
646 RegisterImporter (base_importers_table, typeof (string),
647 typeof (DateTime), importer);
648 }
649  
650 private static void RegisterImporter (
651 IDictionary<Type, IDictionary<Type, ImporterFunc>> table,
652 Type json_type, Type value_type, ImporterFunc importer)
653 {
654 if (! table.ContainsKey (json_type))
655 table.Add (json_type, new Dictionary<Type, ImporterFunc> ());
656  
657 table[json_type][value_type] = importer;
658 }
659  
660 private static void WriteValue (object obj, JsonWriter writer,
661 bool writer_is_private,
662 int depth)
663 {
664 if (depth > max_nesting_depth)
665 throw new JsonException (
666 String.Format ("Max allowed object depth reached while " +
667 "trying to export from type {0}",
668 obj.GetType ()));
669  
670 if (obj == null) {
671 writer.Write (null);
672 return;
673 }
674  
675 if (obj is IJsonWrapper) {
676 if (writer_is_private)
677 writer.TextWriter.Write (((IJsonWrapper) obj).ToJson ());
678 else
679 ((IJsonWrapper) obj).ToJson (writer);
680  
681 return;
682 }
683  
684 if (obj is String) {
685 writer.Write ((string) obj);
686 return;
687 }
688  
689 if (obj is Double) {
690 writer.Write ((double) obj);
691 return;
692 }
693  
694 if (obj is Int32) {
695 writer.Write ((int) obj);
696 return;
697 }
698  
699 if (obj is Boolean) {
700 writer.Write ((bool) obj);
701 return;
702 }
703  
704 if (obj is Int64) {
705 writer.Write ((long) obj);
706 return;
707 }
708  
709 if (obj is Array) {
710 writer.WriteArrayStart ();
711  
712 foreach (object elem in (Array) obj)
713 WriteValue (elem, writer, writer_is_private, depth + 1);
714  
715 writer.WriteArrayEnd ();
716  
717 return;
718 }
719  
720 if (obj is IList) {
721 writer.WriteArrayStart ();
722 foreach (object elem in (IList) obj)
723 WriteValue (elem, writer, writer_is_private, depth + 1);
724 writer.WriteArrayEnd ();
725  
726 return;
727 }
728  
729 if (obj is IDictionary) {
730 writer.WriteObjectStart ();
731 foreach (DictionaryEntry entry in (IDictionary) obj) {
732 writer.WritePropertyName ((string) entry.Key);
733 WriteValue (entry.Value, writer, writer_is_private,
734 depth + 1);
735 }
736 writer.WriteObjectEnd ();
737  
738 return;
739 }
740  
741 Type obj_type = obj.GetType ();
742  
743 // See if there's a custom exporter for the object
744 if (custom_exporters_table.ContainsKey (obj_type)) {
745 ExporterFunc exporter = custom_exporters_table[obj_type];
746 exporter (obj, writer);
747  
748 return;
749 }
750  
751 // If not, maybe there's a base exporter
752 if (base_exporters_table.ContainsKey (obj_type)) {
753 ExporterFunc exporter = base_exporters_table[obj_type];
754 exporter (obj, writer);
755  
756 return;
757 }
758  
759 // Last option, let's see if it's an enum
760 if (obj is Enum) {
761 Type e_type = Enum.GetUnderlyingType (obj_type);
762  
763 if (e_type == typeof (long)
764 || e_type == typeof (uint)
765 || e_type == typeof (ulong))
766 writer.Write ((ulong) obj);
767 else
768 writer.Write ((int) obj);
769  
770 return;
771 }
772  
773 // Okay, so it looks like the input should be exported as an
774 // object
775 AddTypeProperties (obj_type);
776 IList<PropertyMetadata> props = type_properties[obj_type];
777  
778 writer.WriteObjectStart ();
779 foreach (PropertyMetadata p_data in props) {
780 if (p_data.IsField) {
781 writer.WritePropertyName (p_data.Info.Name);
782 WriteValue (((FieldInfo) p_data.Info).GetValue (obj),
783 writer, writer_is_private, depth + 1);
784 }
785 else {
786 PropertyInfo p_info = (PropertyInfo) p_data.Info;
787  
788 if (p_info.CanRead) {
789 writer.WritePropertyName (p_data.Info.Name);
790 WriteValue (p_info.GetValue (obj, null),
791 writer, writer_is_private, depth + 1);
792 }
793 }
794 }
795 writer.WriteObjectEnd ();
796 }
797 #endregion
798  
799  
800 public static string ToJson (object obj)
801 {
802 lock (static_writer_lock) {
803 static_writer.Reset ();
804  
805 WriteValue (obj, static_writer, true, 0);
806  
807 return static_writer.ToString ();
808 }
809 }
810  
811 public static void ToJson (object obj, JsonWriter writer)
812 {
813 WriteValue (obj, writer, false, 0);
814 }
815  
816 public static JsonData ToObject (JsonReader reader)
817 {
818 return (JsonData) ToWrapper (
819 delegate { return new JsonData (); }, reader);
820 }
821  
822 public static JsonData ToObject (TextReader reader)
823 {
824 JsonReader json_reader = new JsonReader (reader);
825  
826 return (JsonData) ToWrapper (
827 delegate { return new JsonData (); }, json_reader);
828 }
829  
830 public static JsonData ToObject (string json)
831 {
832 return (JsonData) ToWrapper (
833 delegate { return new JsonData (); }, json);
834 }
835  
836 public static T ToObject<T> (JsonReader reader)
837 {
838 return (T) ReadValue (typeof (T), reader);
839 }
840  
841 public static T ToObject<T> (TextReader reader)
842 {
843 JsonReader json_reader = new JsonReader (reader);
844  
845 return (T) ReadValue (typeof (T), json_reader);
846 }
847  
848 public static T ToObject<T> (string json)
849 {
850 JsonReader reader = new JsonReader (json);
851  
852 return (T) ReadValue (typeof (T), reader);
853 }
854  
855 public static IJsonWrapper ToWrapper (WrapperFactory factory,
856 JsonReader reader)
857 {
858 return ReadValue (factory, reader);
859 }
860  
861 public static IJsonWrapper ToWrapper (WrapperFactory factory,
862 string json)
863 {
864 JsonReader reader = new JsonReader (json);
865  
866 return ReadValue (factory, reader);
867 }
868  
869 public static void RegisterExporter<T> (ExporterFunc<T> exporter)
870 {
871 ExporterFunc exporter_wrapper =
872 delegate (object obj, JsonWriter writer) {
873 exporter ((T) obj, writer);
874 };
875  
876 custom_exporters_table[typeof (T)] = exporter_wrapper;
877 }
878  
879 public static void RegisterImporter<TJson, TValue> (
880 ImporterFunc<TJson, TValue> importer)
881 {
882 ImporterFunc importer_wrapper =
883 delegate (object input) {
884 return importer ((TJson) input);
885 };
886  
887 RegisterImporter (custom_importers_table, typeof (TJson),
888 typeof (TValue), importer_wrapper);
889 }
890  
891 public static void UnregisterExporters ()
892 {
893 custom_exporters_table.Clear ();
894 }
895  
896 public static void UnregisterImporters ()
897 {
898 custom_importers_table.Clear ();
899 }
900 }
901 }