// Make a parser for value types public static Func <IJsonReader, Type, object> MakeParser(Type type) { System.Diagnostics.Debug.Assert(type.IsValueType); // ParseJson method? var parseJson = ReflectionInfo.FindParseJson(type); if (parseJson != null) { if (parseJson.GetParameters()[0].ParameterType == typeof(IJsonReader)) { var method = new DynamicMethod("invoke_ParseJson", typeof(Object), new Type[] { typeof(IJsonReader), typeof(Type) }, true); var il = method.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, parseJson); il.Emit(OpCodes.Box, type); il.Emit(OpCodes.Ret); return((Func <IJsonReader, Type, object>)method.CreateDelegate(typeof(Func <IJsonReader, Type, object>))); } else { var method = new DynamicMethod("invoke_ParseJson", typeof(Object), new Type[] { typeof(string) }, true); var il = method.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, parseJson); il.Emit(OpCodes.Box, type); il.Emit(OpCodes.Ret); var invoke = (Func <string, object>)method.CreateDelegate(typeof(Func <string, object>)); return((r, t) => { if (r.GetLiteralKind() == LiteralKind.String) { var o = invoke(r.GetLiteralString()); r.NextToken(); return o; } throw new InvalidDataException(string.Format("Expected string literal for type {0}", type.FullName)); }); } } else { // Get the reflection info for this type var ri = ReflectionInfo.GetReflectionInfo(type); if (ri == null) { return(null); } // We'll create setters for each property/field var setters = new Dictionary <string, Action <IJsonReader, object> >(); // Store the value in a pseudo box until it's fully initialized var boxType = typeof(PseudoBox <>).MakeGenericType(type); // Process all members foreach (var m in ri.Members) { // Ignore write only properties var pi = m.Member as PropertyInfo; var fi = m.Member as FieldInfo; if (pi != null && pi.GetSetMethod(true) == null) { continue; } // Create a dynamic method that can do the work var method = new DynamicMethod("dynamic_parser", null, new Type[] { typeof(IJsonReader), typeof(object) }, true); var il = method.GetILGenerator(); // Load the target il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Castclass, boxType); il.Emit(OpCodes.Ldflda, boxType.GetField("value")); // Get the value GenerateGetJsonValue(m, il); // Assign it if (pi != null) { il.Emit(OpCodes.Call, pi.GetSetMethod(true)); } if (fi != null) { il.Emit(OpCodes.Stfld, fi); } // Done il.Emit(OpCodes.Ret); // Store in the map of setters setters.Add(m.JsonKey, (Action <IJsonReader, object>)method.CreateDelegate(typeof(Action <IJsonReader, object>))); } // Create helpers to invoke the interfaces (this is painful but avoids having to really box // the value in order to call the interface). Action <object, IJsonReader> invokeLoading = MakeInterfaceCall(type, typeof(IJsonLoading)); Action <object, IJsonReader> invokeLoaded = MakeInterfaceCall(type, typeof(IJsonLoaded)); Func <object, IJsonReader, string, bool> invokeField = MakeLoadFieldCall(type); // Create the parser Func <IJsonReader, Type, object> parser = (reader, Type) => { // Create pseudobox (ie: new PseudoBox<Type>) var box = DecoratingActivator.CreateInstance(boxType); // Call IJsonLoading if (invokeLoading != null) { invokeLoading(box, reader); } // Read the dictionary reader.ParseDictionary(key => { // Call IJsonLoadField if (invokeField != null && invokeField(box, reader, key)) { return; } // Get a setter and invoke it if found Action <IJsonReader, object> setter; if (setters.TryGetValue(key, out setter)) { setter(reader, box); } }); // IJsonLoaded if (invokeLoaded != null) { invokeLoaded(box, reader); } // Return the value return(((IPseudoBox)box).GetValue()); }; // Done return(parser); } }