|
@@ -1,837 +1,864 @@
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-#if !JSONKIT_NO_EMIT
|
|
|
-
|
|
|
-using System;
|
|
|
-using System.Collections.Generic;
|
|
|
-using System.Linq;
|
|
|
-using System.IO;
|
|
|
-using System.Reflection;
|
|
|
-using System.Globalization;
|
|
|
-using System.Reflection.Emit;
|
|
|
-
|
|
|
-namespace Topten.JsonKit
|
|
|
-{
|
|
|
- static class Emit
|
|
|
- {
|
|
|
-
|
|
|
-
|
|
|
- public static Action<IJsonWriter, object> MakeFormatter(Type type)
|
|
|
- {
|
|
|
- var formatJson = ReflectionInfo.FindFormatJson(type);
|
|
|
- if (formatJson != null)
|
|
|
- {
|
|
|
- var method = new DynamicMethod("invoke_formatJson", null, new Type[] { typeof(IJsonWriter), typeof(Object) }, true);
|
|
|
- var il = method.GetILGenerator();
|
|
|
- if (formatJson.ReturnType == typeof(string))
|
|
|
- {
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ldarg_0);
|
|
|
- il.Emit(OpCodes.Ldarg_1);
|
|
|
- il.Emit(OpCodes.Unbox, type);
|
|
|
- il.Emit(OpCodes.Call, formatJson);
|
|
|
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteStringLiteral"));
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ldarg_1);
|
|
|
- il.Emit(type.IsValueType ? OpCodes.Unbox : OpCodes.Castclass, type);
|
|
|
- il.Emit(OpCodes.Ldarg_0);
|
|
|
- il.Emit(type.IsValueType ? OpCodes.Call : OpCodes.Callvirt, formatJson);
|
|
|
- }
|
|
|
- il.Emit(OpCodes.Ret);
|
|
|
- return (Action<IJsonWriter, object>)method.CreateDelegate(typeof(Action<IJsonWriter, object>));
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
-
|
|
|
- var ri = ReflectionInfo.GetReflectionInfo(type);
|
|
|
- if (ri == null)
|
|
|
- return null;
|
|
|
-
|
|
|
-
|
|
|
- var method = new DynamicMethod("dynamic_formatter", null, new Type[] { typeof(IJsonWriter), typeof(object) }, true);
|
|
|
- var il = method.GetILGenerator();
|
|
|
-
|
|
|
-
|
|
|
- var locTypedObj = il.DeclareLocal(type);
|
|
|
- il.Emit(OpCodes.Ldarg_1);
|
|
|
- il.Emit(type.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, type);
|
|
|
- il.Emit(OpCodes.Stloc, locTypedObj);
|
|
|
-
|
|
|
-
|
|
|
- var locInvariant = il.DeclareLocal(typeof(IFormatProvider));
|
|
|
- il.Emit(OpCodes.Call, typeof(CultureInfo).GetProperty("InvariantCulture").GetGetMethod());
|
|
|
- il.Emit(OpCodes.Stloc, locInvariant);
|
|
|
-
|
|
|
-
|
|
|
- var toStringTypes = new Type[] {
|
|
|
- typeof(int), typeof(uint), typeof(long), typeof(ulong),
|
|
|
- typeof(short), typeof(ushort), typeof(decimal),
|
|
|
- typeof(byte), typeof(sbyte)
|
|
|
- };
|
|
|
-
|
|
|
-
|
|
|
- var otherSupportedTypes = new Type[] {
|
|
|
- typeof(double), typeof(float), typeof(string), typeof(char)
|
|
|
- };
|
|
|
-
|
|
|
-
|
|
|
- if (typeof(IJsonWriting).IsAssignableFrom(type))
|
|
|
- {
|
|
|
- if (type.IsValueType)
|
|
|
- {
|
|
|
- il.Emit(OpCodes.Ldloca, locTypedObj);
|
|
|
- il.Emit(OpCodes.Ldarg_0);
|
|
|
- il.Emit(OpCodes.Call, type.GetInterfaceMap(typeof(IJsonWriting)).TargetMethods[0]);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- il.Emit(OpCodes.Ldloc, locTypedObj);
|
|
|
- il.Emit(OpCodes.Castclass, typeof(IJsonWriting));
|
|
|
- il.Emit(OpCodes.Ldarg_0);
|
|
|
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriting).GetMethod("OnJsonWriting", new Type[] { typeof(IJsonWriter) }));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- foreach (var m in ri.Members)
|
|
|
- {
|
|
|
-
|
|
|
- if (m.Deprecated)
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- var pi = m.Member as PropertyInfo;
|
|
|
- if (pi != null && pi.GetGetMethod(true) == null)
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ldarg_0);
|
|
|
-
|
|
|
-
|
|
|
- var memberType = m.MemberType;
|
|
|
-
|
|
|
-
|
|
|
- if (type.IsValueType)
|
|
|
- {
|
|
|
- il.Emit(OpCodes.Ldloca, locTypedObj);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- il.Emit(OpCodes.Ldloc, locTypedObj);
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- bool NeedValueAddress = (memberType.IsValueType && (toStringTypes.Contains(memberType) || otherSupportedTypes.Contains(memberType)));
|
|
|
- if (Nullable.GetUnderlyingType(memberType) != null)
|
|
|
- {
|
|
|
- NeedValueAddress = true;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- if (pi != null)
|
|
|
- {
|
|
|
-
|
|
|
- if (type.IsValueType)
|
|
|
- il.Emit(OpCodes.Call, pi.GetGetMethod(true));
|
|
|
- else
|
|
|
- il.Emit(OpCodes.Callvirt, pi.GetGetMethod(true));
|
|
|
-
|
|
|
-
|
|
|
- if (NeedValueAddress)
|
|
|
- {
|
|
|
- var locTemp = il.DeclareLocal(memberType);
|
|
|
- il.Emit(OpCodes.Stloc, locTemp);
|
|
|
- il.Emit(OpCodes.Ldloca, locTemp);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- var fi = m.Member as FieldInfo;
|
|
|
- if (fi != null)
|
|
|
- {
|
|
|
- if (NeedValueAddress)
|
|
|
- {
|
|
|
- il.Emit(OpCodes.Ldflda, fi);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- il.Emit(OpCodes.Ldfld, fi);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Label lblFinished = il.DefineLabel();
|
|
|
-
|
|
|
- void EmitWriteKey()
|
|
|
- {
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ldarg_0);
|
|
|
- il.Emit(OpCodes.Ldstr, m.JsonKey);
|
|
|
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteKeyNoEscaping", new Type[] { typeof(string) }));
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- var typeUnderlying = Nullable.GetUnderlyingType(memberType);
|
|
|
- if (typeUnderlying != null)
|
|
|
- {
|
|
|
-
|
|
|
- var lblHasValue = il.DefineLabel();
|
|
|
-
|
|
|
-
|
|
|
- il.Emit(OpCodes.Dup);
|
|
|
- il.Emit(OpCodes.Call, memberType.GetProperty("HasValue").GetGetMethod());
|
|
|
- il.Emit(OpCodes.Brtrue, lblHasValue);
|
|
|
-
|
|
|
-
|
|
|
- if (m.ExcludeIfNull)
|
|
|
- {
|
|
|
- il.Emit(OpCodes.Pop);
|
|
|
- il.Emit(OpCodes.Pop);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
-
|
|
|
- EmitWriteKey();
|
|
|
-
|
|
|
-
|
|
|
- il.Emit(OpCodes.Pop);
|
|
|
- il.Emit(OpCodes.Ldstr, "null");
|
|
|
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteRaw", new Type[] { typeof(string) }));
|
|
|
- }
|
|
|
- il.Emit(OpCodes.Br_S, lblFinished);
|
|
|
-
|
|
|
-
|
|
|
- il.MarkLabel(lblHasValue);
|
|
|
- EmitWriteKey();
|
|
|
- il.Emit(OpCodes.Call, memberType.GetProperty("Value").GetGetMethod());
|
|
|
-
|
|
|
-
|
|
|
- memberType = typeUnderlying;
|
|
|
- NeedValueAddress = (memberType.IsValueType && (toStringTypes.Contains(memberType) || otherSupportedTypes.Contains(memberType)));
|
|
|
-
|
|
|
-
|
|
|
- if (NeedValueAddress)
|
|
|
- {
|
|
|
- var locTemp = il.DeclareLocal(memberType);
|
|
|
- il.Emit(OpCodes.Stloc, locTemp);
|
|
|
- il.Emit(OpCodes.Ldloca, locTemp);
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- if (m.ExcludeIfNull && !type.IsValueType)
|
|
|
- {
|
|
|
- var lblContinue = il.DefineLabel();
|
|
|
- System.Diagnostics.Debug.Assert(!NeedValueAddress);
|
|
|
- il.Emit(OpCodes.Dup);
|
|
|
- il.Emit(OpCodes.Brtrue_S, lblContinue);
|
|
|
-
|
|
|
- il.Emit(OpCodes.Pop);
|
|
|
- il.Emit(OpCodes.Pop);
|
|
|
-
|
|
|
-
|
|
|
- il.Emit(OpCodes.Br_S, lblFinished);
|
|
|
-
|
|
|
- il.MarkLabel(lblContinue);
|
|
|
- }
|
|
|
-
|
|
|
- EmitWriteKey();
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- if (toStringTypes.Contains(memberType))
|
|
|
- {
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ldloc, locInvariant);
|
|
|
- il.Emit(OpCodes.Call, memberType.GetMethod("ToString", new Type[] { typeof(IFormatProvider) }));
|
|
|
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteRaw", new Type[] { typeof(string) }));
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- else if (memberType == typeof(float) || memberType == typeof(double))
|
|
|
- {
|
|
|
- il.Emit(OpCodes.Ldstr, "R");
|
|
|
- il.Emit(OpCodes.Ldloc, locInvariant);
|
|
|
- il.Emit(OpCodes.Call, memberType.GetMethod("ToString", new Type[] { typeof(string), typeof(IFormatProvider) }));
|
|
|
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteRaw", new Type[] { typeof(string) }));
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- else if (memberType == typeof(string))
|
|
|
- {
|
|
|
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteStringLiteral", new Type[] { typeof(string) }));
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- else if (memberType == typeof(char))
|
|
|
- {
|
|
|
- il.Emit(OpCodes.Call, memberType.GetMethod("ToString", new Type[] { }));
|
|
|
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteStringLiteral", new Type[] { typeof(string) }));
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- else if (memberType == typeof(bool))
|
|
|
- {
|
|
|
- var lblTrue = il.DefineLabel();
|
|
|
- var lblCont = il.DefineLabel();
|
|
|
- il.Emit(OpCodes.Brtrue_S, lblTrue);
|
|
|
- il.Emit(OpCodes.Ldstr, "false");
|
|
|
- il.Emit(OpCodes.Br_S, lblCont);
|
|
|
- il.MarkLabel(lblTrue);
|
|
|
- il.Emit(OpCodes.Ldstr, "true");
|
|
|
- il.MarkLabel(lblCont);
|
|
|
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteRaw", new Type[] { typeof(string) }));
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- else
|
|
|
- {
|
|
|
-
|
|
|
- if (memberType.IsValueType)
|
|
|
- {
|
|
|
- il.Emit(OpCodes.Box, memberType);
|
|
|
- }
|
|
|
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteValue", new Type[] { typeof(object) }));
|
|
|
- }
|
|
|
-
|
|
|
- il.MarkLabel(lblFinished);
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- if (typeof(IJsonWritten).IsAssignableFrom(type))
|
|
|
- {
|
|
|
- if (type.IsValueType)
|
|
|
- {
|
|
|
- il.Emit(OpCodes.Ldloca, locTypedObj);
|
|
|
- il.Emit(OpCodes.Ldarg_0);
|
|
|
- il.Emit(OpCodes.Call, type.GetInterfaceMap(typeof(IJsonWritten)).TargetMethods[0]);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- il.Emit(OpCodes.Ldloc, locTypedObj);
|
|
|
- il.Emit(OpCodes.Castclass, typeof(IJsonWriting));
|
|
|
- il.Emit(OpCodes.Ldarg_0);
|
|
|
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriting).GetMethod("OnJsonWritten", new Type[] { typeof(IJsonWriter) }));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ret);
|
|
|
- var impl = (Action<IJsonWriter, object>)method.CreateDelegate(typeof(Action<IJsonWriter, object>));
|
|
|
-
|
|
|
-
|
|
|
- return (w, obj) =>
|
|
|
- {
|
|
|
- w.WriteDictionary(() =>
|
|
|
- {
|
|
|
- impl(w, obj);
|
|
|
- });
|
|
|
- };
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- interface IPseudoBox
|
|
|
- {
|
|
|
- object GetValue();
|
|
|
- }
|
|
|
- [Obfuscation(Exclude = true, ApplyToMembers = true)]
|
|
|
- class PseudoBox<T> : IPseudoBox where T : struct
|
|
|
- {
|
|
|
- public T value = default(T);
|
|
|
- object IPseudoBox.GetValue() { return value; }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- public static Func<IJsonReader, Type, object> MakeParser(Type type)
|
|
|
- {
|
|
|
- System.Diagnostics.Debug.Assert(type.IsValueType);
|
|
|
-
|
|
|
-
|
|
|
- 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
|
|
|
- {
|
|
|
-
|
|
|
- var ri = ReflectionInfo.GetReflectionInfo(type);
|
|
|
- if (ri == null)
|
|
|
- return null;
|
|
|
-
|
|
|
-
|
|
|
- var setters = new Dictionary<string, Action<IJsonReader, object>>();
|
|
|
-
|
|
|
-
|
|
|
- var boxType = typeof(PseudoBox<>).MakeGenericType(type);
|
|
|
-
|
|
|
-
|
|
|
- foreach (var m in ri.Members)
|
|
|
- {
|
|
|
-
|
|
|
- var pi = m.Member as PropertyInfo;
|
|
|
- var fi = m.Member as FieldInfo;
|
|
|
- if (pi != null && pi.GetSetMethod(true) == null)
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- var method = new DynamicMethod("dynamic_parser", null, new Type[] { typeof(IJsonReader), typeof(object) }, true);
|
|
|
- var il = method.GetILGenerator();
|
|
|
-
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ldarg_1);
|
|
|
- il.Emit(OpCodes.Castclass, boxType);
|
|
|
- il.Emit(OpCodes.Ldflda, boxType.GetField("value"));
|
|
|
-
|
|
|
-
|
|
|
- GenerateGetJsonValue(m, il);
|
|
|
-
|
|
|
-
|
|
|
- if (pi != null)
|
|
|
- il.Emit(OpCodes.Call, pi.GetSetMethod(true));
|
|
|
- if (fi != null)
|
|
|
- il.Emit(OpCodes.Stfld, fi);
|
|
|
-
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ret);
|
|
|
-
|
|
|
-
|
|
|
- setters.Add(m.JsonKey, (Action<IJsonReader, object>)method.CreateDelegate(typeof(Action<IJsonReader, object>)));
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- Action<object, IJsonReader> invokeLoading = MakeInterfaceCall(type, typeof(IJsonLoading));
|
|
|
- Action<object, IJsonReader> invokeLoaded = MakeInterfaceCall(type, typeof(IJsonLoaded));
|
|
|
- Func<object, IJsonReader, string, bool> invokeField = MakeLoadFieldCall(type);
|
|
|
-
|
|
|
-
|
|
|
- Func<IJsonReader, Type, object> parser = (reader, Type) =>
|
|
|
- {
|
|
|
-
|
|
|
- var box = DecoratingActivator.CreateInstance(boxType);
|
|
|
-
|
|
|
-
|
|
|
- if (invokeLoading != null)
|
|
|
- invokeLoading(box, reader);
|
|
|
-
|
|
|
-
|
|
|
- reader.ParseDictionary(key =>
|
|
|
- {
|
|
|
-
|
|
|
- if (invokeField != null && invokeField(box, reader, key))
|
|
|
- return;
|
|
|
-
|
|
|
-
|
|
|
- Action<IJsonReader, object> setter;
|
|
|
- if (setters.TryGetValue(key, out setter))
|
|
|
- {
|
|
|
- setter(reader, box);
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
-
|
|
|
- if (invokeLoaded != null)
|
|
|
- invokeLoaded(box, reader);
|
|
|
-
|
|
|
-
|
|
|
- return ((IPseudoBox)box).GetValue();
|
|
|
- };
|
|
|
-
|
|
|
-
|
|
|
- return parser;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- static Action<object, IJsonReader> MakeInterfaceCall(Type type, Type tItf)
|
|
|
- {
|
|
|
-
|
|
|
- if (!tItf.IsAssignableFrom(type))
|
|
|
- return null;
|
|
|
-
|
|
|
-
|
|
|
- var boxType = typeof(PseudoBox<>).MakeGenericType(type);
|
|
|
-
|
|
|
-
|
|
|
- var method = new DynamicMethod("dynamic_invoke_" + tItf.Name, null, new Type[] { typeof(object), typeof(IJsonReader) }, true);
|
|
|
- var il = method.GetILGenerator();
|
|
|
-
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ldarg_0);
|
|
|
- il.Emit(OpCodes.Castclass, boxType);
|
|
|
- il.Emit(OpCodes.Ldflda, boxType.GetField("value"));
|
|
|
- il.Emit(OpCodes.Ldarg_1);
|
|
|
- il.Emit(OpCodes.Call, type.GetInterfaceMap(tItf).TargetMethods[0]);
|
|
|
- il.Emit(OpCodes.Ret);
|
|
|
-
|
|
|
-
|
|
|
- return (Action<object, IJsonReader>)method.CreateDelegate(typeof(Action<object, IJsonReader>));
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- static Func<object, IJsonReader, string, bool> MakeLoadFieldCall(Type type)
|
|
|
- {
|
|
|
-
|
|
|
- var tItf = typeof(IJsonLoadField);
|
|
|
- if (!tItf.IsAssignableFrom(type))
|
|
|
- return null;
|
|
|
-
|
|
|
-
|
|
|
- var boxType = typeof(PseudoBox<>).MakeGenericType(type);
|
|
|
-
|
|
|
-
|
|
|
- var method = new DynamicMethod("dynamic_invoke_" + tItf.Name, typeof(bool), new Type[] { typeof(object), typeof(IJsonReader), typeof(string) }, true);
|
|
|
- var il = method.GetILGenerator();
|
|
|
-
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ldarg_0);
|
|
|
- il.Emit(OpCodes.Castclass, boxType);
|
|
|
- il.Emit(OpCodes.Ldflda, boxType.GetField("value"));
|
|
|
- il.Emit(OpCodes.Ldarg_1);
|
|
|
- il.Emit(OpCodes.Ldarg_2);
|
|
|
- il.Emit(OpCodes.Call, type.GetInterfaceMap(tItf).TargetMethods[0]);
|
|
|
- il.Emit(OpCodes.Ret);
|
|
|
-
|
|
|
-
|
|
|
- return (Func<object, IJsonReader, string, bool>)method.CreateDelegate(typeof(Func<object, IJsonReader, string, bool>));
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- public static Action<IJsonReader, object> MakeIntoParser(Type type)
|
|
|
- {
|
|
|
- System.Diagnostics.Debug.Assert(!type.IsValueType);
|
|
|
-
|
|
|
-
|
|
|
- var ri = ReflectionInfo.GetReflectionInfo(type);
|
|
|
- if (ri == null)
|
|
|
- return null;
|
|
|
-
|
|
|
-
|
|
|
- var setters = new Dictionary<string, Action<IJsonReader, object>>();
|
|
|
-
|
|
|
-
|
|
|
- foreach (var m in ri.Members)
|
|
|
- {
|
|
|
-
|
|
|
- var pi = m.Member as PropertyInfo;
|
|
|
- var fi = m.Member as FieldInfo;
|
|
|
- if (pi != null && pi.GetSetMethod(true) == null)
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- if (pi != null && pi.GetGetMethod(true) == null && m.KeepInstance)
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- var method = new DynamicMethod("dynamic_parser", null, new Type[] { typeof(IJsonReader), typeof(object) }, true);
|
|
|
- var il = method.GetILGenerator();
|
|
|
-
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ldarg_1);
|
|
|
- il.Emit(OpCodes.Castclass, type);
|
|
|
-
|
|
|
-
|
|
|
- if (m.KeepInstance)
|
|
|
- {
|
|
|
-
|
|
|
- il.Emit(OpCodes.Dup);
|
|
|
- if (pi != null)
|
|
|
- il.Emit(OpCodes.Callvirt, pi.GetGetMethod(true));
|
|
|
- else
|
|
|
- il.Emit(OpCodes.Ldfld, fi);
|
|
|
-
|
|
|
- var existingInstance = il.DeclareLocal(m.MemberType);
|
|
|
- var lblExistingInstanceNull = il.DefineLabel();
|
|
|
-
|
|
|
-
|
|
|
- il.Emit(OpCodes.Dup);
|
|
|
- il.Emit(OpCodes.Stloc, existingInstance);
|
|
|
-
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ldnull);
|
|
|
- il.Emit(OpCodes.Ceq);
|
|
|
- il.Emit(OpCodes.Brtrue_S, lblExistingInstanceNull);
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ldarg_0);
|
|
|
- il.Emit(OpCodes.Ldloc, existingInstance);
|
|
|
- il.Emit(OpCodes.Callvirt, typeof(IJsonReader).GetMethod("ParseInto", new Type[] { typeof(Object) }));
|
|
|
-
|
|
|
- il.Emit(OpCodes.Pop);
|
|
|
- il.Emit(OpCodes.Ret);
|
|
|
-
|
|
|
- il.MarkLabel(lblExistingInstanceNull);
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- GenerateGetJsonValue(m, il);
|
|
|
-
|
|
|
-
|
|
|
- if (pi != null)
|
|
|
- il.Emit(OpCodes.Callvirt, pi.GetSetMethod(true));
|
|
|
- if (fi != null)
|
|
|
- il.Emit(OpCodes.Stfld, fi);
|
|
|
-
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ret);
|
|
|
-
|
|
|
-
|
|
|
- setters.Add(m.JsonKey, (Action<IJsonReader, object>)method.CreateDelegate(typeof(Action<IJsonReader, object>)));
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- Action<IJsonReader, object> parseInto = (reader, obj) =>
|
|
|
- {
|
|
|
-
|
|
|
- var loading = obj as IJsonLoading;
|
|
|
- if (loading != null)
|
|
|
- loading.OnJsonLoading(reader);
|
|
|
-
|
|
|
-
|
|
|
- var lf = obj as IJsonLoadField;
|
|
|
-
|
|
|
-
|
|
|
- reader.ParseDictionary(key =>
|
|
|
- {
|
|
|
-
|
|
|
- if (lf != null && lf.OnJsonField(reader, key))
|
|
|
- return;
|
|
|
-
|
|
|
-
|
|
|
- Action<IJsonReader, object> setter;
|
|
|
- if (setters.TryGetValue(key, out setter))
|
|
|
- {
|
|
|
- setter(reader, obj);
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
-
|
|
|
- var loaded = obj as IJsonLoaded;
|
|
|
- if (loaded != null)
|
|
|
- loaded.OnJsonLoaded(reader);
|
|
|
- };
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- RegisterIntoParser(type, parseInto);
|
|
|
-
|
|
|
-
|
|
|
- return parseInto;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- static void RegisterIntoParser(Type type, Action<IJsonReader, object> parseInto)
|
|
|
- {
|
|
|
-
|
|
|
- var con = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[0], null);
|
|
|
- if (con == null)
|
|
|
- return;
|
|
|
-
|
|
|
-
|
|
|
- var method = new DynamicMethod("dynamic_factory", typeof(object), new Type[] { typeof(IJsonReader), typeof(Action<IJsonReader, object>) }, true);
|
|
|
- var il = method.GetILGenerator();
|
|
|
-
|
|
|
-
|
|
|
- var locObj = il.DeclareLocal(typeof(object));
|
|
|
- il.Emit(OpCodes.Newobj, con);
|
|
|
-
|
|
|
- il.Emit(OpCodes.Dup);
|
|
|
-
|
|
|
- il.Emit(OpCodes.Stloc, locObj);
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ldarg_1);
|
|
|
- il.Emit(OpCodes.Ldarg_0);
|
|
|
- il.Emit(OpCodes.Ldloc, locObj);
|
|
|
- il.Emit(OpCodes.Callvirt, typeof(Action<IJsonReader, object>).GetMethod("Invoke"));
|
|
|
- il.Emit(OpCodes.Ret);
|
|
|
-
|
|
|
- var factory = (Func<IJsonReader, Action<IJsonReader, object>, object>)method.CreateDelegate(typeof(Func<IJsonReader, Action<IJsonReader, object>, object>));
|
|
|
-
|
|
|
- Json.RegisterParser(type, (reader, type2) =>
|
|
|
- {
|
|
|
- return factory(reader, parseInto);
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- private static void GenerateGetJsonValue(JsonMemberInfo m, ILGenerator il)
|
|
|
- {
|
|
|
- Action<string> generateCallToHelper = helperName =>
|
|
|
- {
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ldarg_0);
|
|
|
- il.Emit(OpCodes.Call, typeof(Emit).GetMethod(helperName, new Type[] { typeof(IJsonReader) }));
|
|
|
-
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ldarg_0);
|
|
|
- il.Emit(OpCodes.Callvirt, typeof(IJsonReader).GetMethod("NextToken", new Type[] { }));
|
|
|
- };
|
|
|
-
|
|
|
- Type[] numericTypes = new Type[] {
|
|
|
- typeof(int), typeof(uint), typeof(long), typeof(ulong),
|
|
|
- typeof(short), typeof(ushort), typeof(decimal),
|
|
|
- typeof(byte), typeof(sbyte),
|
|
|
- typeof(double), typeof(float)
|
|
|
- };
|
|
|
-
|
|
|
- if (m.MemberType == typeof(string))
|
|
|
- {
|
|
|
- generateCallToHelper("GetLiteralString");
|
|
|
- }
|
|
|
-
|
|
|
- else if (m.MemberType == typeof(bool))
|
|
|
- {
|
|
|
- generateCallToHelper("GetLiteralBool");
|
|
|
- }
|
|
|
-
|
|
|
- else if (m.MemberType == typeof(char))
|
|
|
- {
|
|
|
- generateCallToHelper("GetLiteralChar");
|
|
|
- }
|
|
|
-
|
|
|
- else if (numericTypes.Contains(m.MemberType))
|
|
|
- {
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ldarg_0);
|
|
|
- il.Emit(OpCodes.Call, typeof(Emit).GetMethod("GetLiteralNumber", new Type[] { typeof(IJsonReader) }));
|
|
|
-
|
|
|
-
|
|
|
- il.Emit(OpCodes.Call, typeof(CultureInfo).GetProperty("InvariantCulture").GetGetMethod());
|
|
|
- il.Emit(OpCodes.Call, m.MemberType.GetMethod("Parse", new Type[] { typeof(string), typeof(IFormatProvider) }));
|
|
|
-
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ldarg_0);
|
|
|
- il.Emit(OpCodes.Callvirt, typeof(IJsonReader).GetMethod("NextToken", new Type[] { }));
|
|
|
- }
|
|
|
-
|
|
|
- else
|
|
|
- {
|
|
|
- il.Emit(OpCodes.Ldarg_0);
|
|
|
- il.Emit(OpCodes.Ldtoken, m.MemberType);
|
|
|
- il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) }));
|
|
|
- il.Emit(OpCodes.Callvirt, typeof(IJsonReader).GetMethod("Parse", new Type[] { typeof(Type) }));
|
|
|
- il.Emit(m.MemberType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, m.MemberType);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- [Obfuscation(Exclude = true)]
|
|
|
- public static bool GetLiteralBool(IJsonReader r)
|
|
|
- {
|
|
|
- switch (r.GetLiteralKind())
|
|
|
- {
|
|
|
- case LiteralKind.True:
|
|
|
- return true;
|
|
|
-
|
|
|
- case LiteralKind.False:
|
|
|
- return false;
|
|
|
-
|
|
|
- default:
|
|
|
- throw new InvalidDataException("expected a boolean value");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- [Obfuscation(Exclude = true)]
|
|
|
- public static char GetLiteralChar(IJsonReader r)
|
|
|
- {
|
|
|
- if (r.GetLiteralKind() != LiteralKind.String)
|
|
|
- throw new InvalidDataException("expected a single character string literal");
|
|
|
- var str = r.GetLiteralString();
|
|
|
- if (str == null || str.Length != 1)
|
|
|
- throw new InvalidDataException("expected a single character string literal");
|
|
|
-
|
|
|
- return str[0];
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- [Obfuscation(Exclude = true)]
|
|
|
- public static string GetLiteralString(IJsonReader r)
|
|
|
- {
|
|
|
- switch (r.GetLiteralKind())
|
|
|
- {
|
|
|
- case LiteralKind.Null: return null;
|
|
|
- case LiteralKind.String: return r.GetLiteralString();
|
|
|
- }
|
|
|
- throw new InvalidDataException("expected a string literal");
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- [Obfuscation(Exclude = true)]
|
|
|
- public static string GetLiteralNumber(IJsonReader r)
|
|
|
- {
|
|
|
- switch (r.GetLiteralKind())
|
|
|
- {
|
|
|
- case LiteralKind.SignedInteger:
|
|
|
- case LiteralKind.UnsignedInteger:
|
|
|
- case LiteralKind.FloatingPoint:
|
|
|
- return r.GetLiteralString();
|
|
|
- }
|
|
|
- throw new InvalidDataException("expected a numeric literal");
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#if !JSONKIT_NO_EMIT
|
|
|
+
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Linq;
|
|
|
+using System.IO;
|
|
|
+using System.Reflection;
|
|
|
+using System.Globalization;
|
|
|
+using System.Reflection.Emit;
|
|
|
+
|
|
|
+namespace Topten.JsonKit
|
|
|
+{
|
|
|
+ static class Emit
|
|
|
+ {
|
|
|
+
|
|
|
+
|
|
|
+ public static Action<IJsonWriter, object> MakeFormatter(Type type)
|
|
|
+ {
|
|
|
+ var formatJson = ReflectionInfo.FindFormatJson(type);
|
|
|
+ if (formatJson != null)
|
|
|
+ {
|
|
|
+ var method = new DynamicMethod("invoke_formatJson", null, new Type[] { typeof(IJsonWriter), typeof(Object) }, true);
|
|
|
+ var il = method.GetILGenerator();
|
|
|
+ if (formatJson.ReturnType == typeof(string))
|
|
|
+ {
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(OpCodes.Ldarg_1);
|
|
|
+ il.Emit(OpCodes.Unbox, type);
|
|
|
+ il.Emit(OpCodes.Call, formatJson);
|
|
|
+ il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteStringLiteral"));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldarg_1);
|
|
|
+ il.Emit(type.IsValueType ? OpCodes.Unbox : OpCodes.Castclass, type);
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(type.IsValueType ? OpCodes.Call : OpCodes.Callvirt, formatJson);
|
|
|
+ }
|
|
|
+ il.Emit(OpCodes.Ret);
|
|
|
+ return (Action<IJsonWriter, object>)method.CreateDelegate(typeof(Action<IJsonWriter, object>));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+
|
|
|
+ var ri = ReflectionInfo.GetReflectionInfo(type);
|
|
|
+ if (ri == null)
|
|
|
+ return null;
|
|
|
+
|
|
|
+
|
|
|
+ var method = new DynamicMethod("dynamic_formatter", null, new Type[] { typeof(IJsonWriter), typeof(object) }, true);
|
|
|
+ var il = method.GetILGenerator();
|
|
|
+
|
|
|
+
|
|
|
+ var locTypedObj = il.DeclareLocal(type);
|
|
|
+ il.Emit(OpCodes.Ldarg_1);
|
|
|
+ il.Emit(type.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, type);
|
|
|
+ il.Emit(OpCodes.Stloc, locTypedObj);
|
|
|
+
|
|
|
+
|
|
|
+ var locInvariant = il.DeclareLocal(typeof(IFormatProvider));
|
|
|
+ il.Emit(OpCodes.Call, typeof(CultureInfo).GetProperty("InvariantCulture").GetGetMethod());
|
|
|
+ il.Emit(OpCodes.Stloc, locInvariant);
|
|
|
+
|
|
|
+
|
|
|
+ var toStringTypes = new Type[] {
|
|
|
+ typeof(int), typeof(uint), typeof(long), typeof(ulong),
|
|
|
+ typeof(short), typeof(ushort), typeof(decimal),
|
|
|
+ typeof(byte), typeof(sbyte)
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ var otherSupportedTypes = new Type[] {
|
|
|
+ typeof(double), typeof(float), typeof(string), typeof(char)
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ if (typeof(IJsonWriting).IsAssignableFrom(type))
|
|
|
+ {
|
|
|
+ if (type.IsValueType)
|
|
|
+ {
|
|
|
+ il.Emit(OpCodes.Ldloca, locTypedObj);
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(OpCodes.Call, type.GetInterfaceMap(typeof(IJsonWriting)).TargetMethods[0]);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ il.Emit(OpCodes.Ldloc, locTypedObj);
|
|
|
+ il.Emit(OpCodes.Castclass, typeof(IJsonWriting));
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(OpCodes.Callvirt, typeof(IJsonWriting).GetMethod("OnJsonWriting", new Type[] { typeof(IJsonWriter) }));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ foreach (var m in ri.Members)
|
|
|
+ {
|
|
|
+
|
|
|
+ if (m.Deprecated)
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ var pi = m.Member as PropertyInfo;
|
|
|
+ if (pi != null && pi.GetGetMethod(true) == null)
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ var memberType = m.MemberType;
|
|
|
+
|
|
|
+
|
|
|
+ LocalBuilder locValue = il.DeclareLocal(memberType);
|
|
|
+ il.Emit(type.IsValueType ? OpCodes.Ldloca : OpCodes.Ldloc, locTypedObj);
|
|
|
+ if (pi != null)
|
|
|
+ {
|
|
|
+ il.Emit(type.IsValueType ? OpCodes.Call : OpCodes.Callvirt, pi.GetGetMethod(true));
|
|
|
+ }
|
|
|
+ if (m.Member is FieldInfo fi)
|
|
|
+ {
|
|
|
+ il.Emit(OpCodes.Ldfld, fi);
|
|
|
+ }
|
|
|
+ il.Emit(OpCodes.Stloc, locValue);
|
|
|
+
|
|
|
+
|
|
|
+ Label lblFinishedMember = il.DefineLabel();
|
|
|
+
|
|
|
+
|
|
|
+ void EmitWriteKey()
|
|
|
+ {
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(OpCodes.Ldstr, m.JsonKey);
|
|
|
+ il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteKeyNoEscaping", new Type[] { typeof(string) }));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ var typeUnderlying = Nullable.GetUnderlyingType(memberType);
|
|
|
+ if (typeUnderlying != null)
|
|
|
+ {
|
|
|
+
|
|
|
+ var lblHasValue = il.DefineLabel();
|
|
|
+
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldloca, locValue);
|
|
|
+ il.Emit(OpCodes.Call, memberType.GetProperty("HasValue").GetGetMethod());
|
|
|
+ il.Emit(OpCodes.Brtrue, lblHasValue);
|
|
|
+
|
|
|
+
|
|
|
+ if (!m.ExcludeIfNull)
|
|
|
+ {
|
|
|
+
|
|
|
+ EmitWriteKey();
|
|
|
+
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(OpCodes.Ldstr, "null");
|
|
|
+ il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteRaw", new Type[] { typeof(string) }));
|
|
|
+ }
|
|
|
+ il.Emit(OpCodes.Br_S, lblFinishedMember);
|
|
|
+
|
|
|
+
|
|
|
+ il.MarkLabel(lblHasValue);
|
|
|
+ il.Emit(OpCodes.Ldloca, locValue);
|
|
|
+ il.Emit(OpCodes.Call, memberType.GetProperty("Value").GetGetMethod());
|
|
|
+
|
|
|
+
|
|
|
+ locValue = il.DeclareLocal(typeUnderlying);
|
|
|
+ il.Emit(OpCodes.Stloc, locValue);
|
|
|
+ memberType = typeUnderlying;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (m.ExcludeIfNull && !type.IsValueType)
|
|
|
+ {
|
|
|
+ il.Emit(OpCodes.Ldloc, locValue);
|
|
|
+ il.Emit(OpCodes.Brfalse_S, lblFinishedMember);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (m.ExcludeIfEquals != null)
|
|
|
+ {
|
|
|
+ il.Emit(OpCodes.Ldloc, locValue);
|
|
|
+ var targetValue = Convert.ChangeType(m.ExcludeIfEquals, m.MemberType);
|
|
|
+ LoadContantFromObject(il, targetValue);
|
|
|
+ il.Emit(OpCodes.Ceq);
|
|
|
+ il.Emit(OpCodes.Brtrue_S, lblFinishedMember);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (toStringTypes.Contains(memberType))
|
|
|
+ {
|
|
|
+ EmitWriteKey();
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(memberType.IsValueType ? OpCodes.Ldloca : OpCodes.Ldloc, locValue);
|
|
|
+ il.Emit(OpCodes.Ldloc, locInvariant);
|
|
|
+ il.Emit(OpCodes.Call, memberType.GetMethod("ToString", new Type[] { typeof(IFormatProvider) }));
|
|
|
+ il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteRaw", new Type[] { typeof(string) }));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ else if (memberType == typeof(float) || memberType == typeof(double))
|
|
|
+ {
|
|
|
+ EmitWriteKey();
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(memberType.IsValueType ? OpCodes.Ldloca : OpCodes.Ldloc, locValue);
|
|
|
+ il.Emit(OpCodes.Ldstr, "R");
|
|
|
+ il.Emit(OpCodes.Ldloc, locInvariant);
|
|
|
+ il.Emit(OpCodes.Call, memberType.GetMethod("ToString", new Type[] { typeof(string), typeof(IFormatProvider) }));
|
|
|
+ il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteRaw", new Type[] { typeof(string) }));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ else if (memberType == typeof(string))
|
|
|
+ {
|
|
|
+ EmitWriteKey();
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(OpCodes.Ldloc, locValue);
|
|
|
+ il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteStringLiteral", new Type[] { typeof(string) }));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ else if (memberType == typeof(char))
|
|
|
+ {
|
|
|
+ EmitWriteKey();
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(OpCodes.Ldloca, locValue);
|
|
|
+ il.Emit(OpCodes.Call, memberType.GetMethod("ToString", new Type[] { }));
|
|
|
+ il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteStringLiteral", new Type[] { typeof(string) }));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ else if (memberType == typeof(bool))
|
|
|
+ {
|
|
|
+ EmitWriteKey();
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ var lblTrue = il.DefineLabel();
|
|
|
+ var lblCont = il.DefineLabel();
|
|
|
+ il.Emit(OpCodes.Ldloc, locValue);
|
|
|
+ il.Emit(OpCodes.Brtrue_S, lblTrue);
|
|
|
+ il.Emit(OpCodes.Ldstr, "false");
|
|
|
+ il.Emit(OpCodes.Br_S, lblCont);
|
|
|
+ il.MarkLabel(lblTrue);
|
|
|
+ il.Emit(OpCodes.Ldstr, "true");
|
|
|
+ il.MarkLabel(lblCont);
|
|
|
+ il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteRaw", new Type[] { typeof(string) }));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ else
|
|
|
+ {
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldloc, locValue);
|
|
|
+ if (memberType.IsValueType)
|
|
|
+ il.Emit(OpCodes.Box, memberType);
|
|
|
+
|
|
|
+
|
|
|
+ if (m.ExcludeIfEmpty)
|
|
|
+ {
|
|
|
+ il.Emit(OpCodes.Ldstr, m.JsonKey);
|
|
|
+ il.Emit(OpCodes.Call, typeof(Emit).GetMethod("WriteKeyAndValueCheckIfEmpty"));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ EmitWriteKey();
|
|
|
+ il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteValue", new Type[] { typeof(object) }));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ il.MarkLabel(lblFinishedMember);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (typeof(IJsonWritten).IsAssignableFrom(type))
|
|
|
+ {
|
|
|
+ if (type.IsValueType)
|
|
|
+ {
|
|
|
+ il.Emit(OpCodes.Ldloca, locTypedObj);
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(OpCodes.Call, type.GetInterfaceMap(typeof(IJsonWritten)).TargetMethods[0]);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ il.Emit(OpCodes.Ldloc, locTypedObj);
|
|
|
+ il.Emit(OpCodes.Castclass, typeof(IJsonWriting));
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(OpCodes.Callvirt, typeof(IJsonWriting).GetMethod("OnJsonWritten", new Type[] { typeof(IJsonWriter) }));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ret);
|
|
|
+ var impl = (Action<IJsonWriter, object>)method.CreateDelegate(typeof(Action<IJsonWriter, object>));
|
|
|
+
|
|
|
+
|
|
|
+ return (w, obj) =>
|
|
|
+ {
|
|
|
+ w.WriteDictionary(() =>
|
|
|
+ {
|
|
|
+ impl(w, obj);
|
|
|
+ });
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static void LoadContantFromObject(ILGenerator il, object value)
|
|
|
+ {
|
|
|
+ switch (Type.GetTypeCode(value.GetType()))
|
|
|
+ {
|
|
|
+ case TypeCode.Boolean:
|
|
|
+ il.Emit(OpCodes.Ldc_I4, ((bool)value) ? 1 : 0);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TypeCode.Char:
|
|
|
+ case TypeCode.SByte:
|
|
|
+ case TypeCode.Byte:
|
|
|
+ case TypeCode.Int16:
|
|
|
+ case TypeCode.UInt16:
|
|
|
+ case TypeCode.Int32:
|
|
|
+ case TypeCode.UInt32:
|
|
|
+ il.Emit(OpCodes.Ldc_I4, (int)value);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TypeCode.Int64:
|
|
|
+ case TypeCode.UInt64:
|
|
|
+ il.Emit(OpCodes.Ldc_I8, (long)value);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TypeCode.Single:
|
|
|
+ il.Emit(OpCodes.Ldc_R4, (float)value);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TypeCode.Double:
|
|
|
+ il.Emit(OpCodes.Ldc_R8, (double)value);
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ throw new InvalidOperationException($"JsonKit doesn't support the type `{value.GetType().ToString()}` for ExcludeIfEquals");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void WriteKeyAndValueCheckIfEmpty(IJsonWriter w, object o, string key)
|
|
|
+ {
|
|
|
+ if (o == null)
|
|
|
+ return;
|
|
|
+
|
|
|
+
|
|
|
+ if (o is System.Collections.IEnumerable e)
|
|
|
+ {
|
|
|
+ if (!e.GetEnumerator().MoveNext())
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ w.WriteKeyNoEscaping(key);
|
|
|
+ w.WriteValue(o);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ interface IPseudoBox
|
|
|
+ {
|
|
|
+ object GetValue();
|
|
|
+ }
|
|
|
+ [Obfuscation(Exclude = true, ApplyToMembers = true)]
|
|
|
+ class PseudoBox<T> : IPseudoBox where T : struct
|
|
|
+ {
|
|
|
+ public T value = default(T);
|
|
|
+ object IPseudoBox.GetValue() { return value; }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ public static Func<IJsonReader, Type, object> MakeParser(Type type)
|
|
|
+ {
|
|
|
+ System.Diagnostics.Debug.Assert(type.IsValueType);
|
|
|
+
|
|
|
+
|
|
|
+ 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
|
|
|
+ {
|
|
|
+
|
|
|
+ var ri = ReflectionInfo.GetReflectionInfo(type);
|
|
|
+ if (ri == null)
|
|
|
+ return null;
|
|
|
+
|
|
|
+
|
|
|
+ var setters = new Dictionary<string, Action<IJsonReader, object>>();
|
|
|
+
|
|
|
+
|
|
|
+ var boxType = typeof(PseudoBox<>).MakeGenericType(type);
|
|
|
+
|
|
|
+
|
|
|
+ foreach (var m in ri.Members)
|
|
|
+ {
|
|
|
+
|
|
|
+ var pi = m.Member as PropertyInfo;
|
|
|
+ var fi = m.Member as FieldInfo;
|
|
|
+ if (pi != null && pi.GetSetMethod(true) == null)
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ var method = new DynamicMethod("dynamic_parser", null, new Type[] { typeof(IJsonReader), typeof(object) }, true);
|
|
|
+ var il = method.GetILGenerator();
|
|
|
+
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldarg_1);
|
|
|
+ il.Emit(OpCodes.Castclass, boxType);
|
|
|
+ il.Emit(OpCodes.Ldflda, boxType.GetField("value"));
|
|
|
+
|
|
|
+
|
|
|
+ GenerateGetJsonValue(m, il);
|
|
|
+
|
|
|
+
|
|
|
+ if (pi != null)
|
|
|
+ il.Emit(OpCodes.Call, pi.GetSetMethod(true));
|
|
|
+ if (fi != null)
|
|
|
+ il.Emit(OpCodes.Stfld, fi);
|
|
|
+
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ret);
|
|
|
+
|
|
|
+
|
|
|
+ setters.Add(m.JsonKey, (Action<IJsonReader, object>)method.CreateDelegate(typeof(Action<IJsonReader, object>)));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ Action<object, IJsonReader> invokeLoading = MakeInterfaceCall(type, typeof(IJsonLoading));
|
|
|
+ Action<object, IJsonReader> invokeLoaded = MakeInterfaceCall(type, typeof(IJsonLoaded));
|
|
|
+ Func<object, IJsonReader, string, bool> invokeField = MakeLoadFieldCall(type);
|
|
|
+
|
|
|
+
|
|
|
+ Func<IJsonReader, Type, object> parser = (reader, Type) =>
|
|
|
+ {
|
|
|
+
|
|
|
+ var box = DecoratingActivator.CreateInstance(boxType);
|
|
|
+
|
|
|
+
|
|
|
+ if (invokeLoading != null)
|
|
|
+ invokeLoading(box, reader);
|
|
|
+
|
|
|
+
|
|
|
+ reader.ParseDictionary(key =>
|
|
|
+ {
|
|
|
+
|
|
|
+ if (invokeField != null && invokeField(box, reader, key))
|
|
|
+ return;
|
|
|
+
|
|
|
+
|
|
|
+ Action<IJsonReader, object> setter;
|
|
|
+ if (setters.TryGetValue(key, out setter))
|
|
|
+ {
|
|
|
+ setter(reader, box);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ if (invokeLoaded != null)
|
|
|
+ invokeLoaded(box, reader);
|
|
|
+
|
|
|
+
|
|
|
+ return ((IPseudoBox)box).GetValue();
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ return parser;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ static Action<object, IJsonReader> MakeInterfaceCall(Type type, Type tItf)
|
|
|
+ {
|
|
|
+
|
|
|
+ if (!tItf.IsAssignableFrom(type))
|
|
|
+ return null;
|
|
|
+
|
|
|
+
|
|
|
+ var boxType = typeof(PseudoBox<>).MakeGenericType(type);
|
|
|
+
|
|
|
+
|
|
|
+ var method = new DynamicMethod("dynamic_invoke_" + tItf.Name, null, new Type[] { typeof(object), typeof(IJsonReader) }, true);
|
|
|
+ var il = method.GetILGenerator();
|
|
|
+
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(OpCodes.Castclass, boxType);
|
|
|
+ il.Emit(OpCodes.Ldflda, boxType.GetField("value"));
|
|
|
+ il.Emit(OpCodes.Ldarg_1);
|
|
|
+ il.Emit(OpCodes.Call, type.GetInterfaceMap(tItf).TargetMethods[0]);
|
|
|
+ il.Emit(OpCodes.Ret);
|
|
|
+
|
|
|
+
|
|
|
+ return (Action<object, IJsonReader>)method.CreateDelegate(typeof(Action<object, IJsonReader>));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ static Func<object, IJsonReader, string, bool> MakeLoadFieldCall(Type type)
|
|
|
+ {
|
|
|
+
|
|
|
+ var tItf = typeof(IJsonLoadField);
|
|
|
+ if (!tItf.IsAssignableFrom(type))
|
|
|
+ return null;
|
|
|
+
|
|
|
+
|
|
|
+ var boxType = typeof(PseudoBox<>).MakeGenericType(type);
|
|
|
+
|
|
|
+
|
|
|
+ var method = new DynamicMethod("dynamic_invoke_" + tItf.Name, typeof(bool), new Type[] { typeof(object), typeof(IJsonReader), typeof(string) }, true);
|
|
|
+ var il = method.GetILGenerator();
|
|
|
+
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(OpCodes.Castclass, boxType);
|
|
|
+ il.Emit(OpCodes.Ldflda, boxType.GetField("value"));
|
|
|
+ il.Emit(OpCodes.Ldarg_1);
|
|
|
+ il.Emit(OpCodes.Ldarg_2);
|
|
|
+ il.Emit(OpCodes.Call, type.GetInterfaceMap(tItf).TargetMethods[0]);
|
|
|
+ il.Emit(OpCodes.Ret);
|
|
|
+
|
|
|
+
|
|
|
+ return (Func<object, IJsonReader, string, bool>)method.CreateDelegate(typeof(Func<object, IJsonReader, string, bool>));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public static Action<IJsonReader, object> MakeIntoParser(Type type)
|
|
|
+ {
|
|
|
+ System.Diagnostics.Debug.Assert(!type.IsValueType);
|
|
|
+
|
|
|
+
|
|
|
+ var ri = ReflectionInfo.GetReflectionInfo(type);
|
|
|
+ if (ri == null)
|
|
|
+ return null;
|
|
|
+
|
|
|
+
|
|
|
+ var setters = new Dictionary<string, Action<IJsonReader, object>>();
|
|
|
+
|
|
|
+
|
|
|
+ foreach (var m in ri.Members)
|
|
|
+ {
|
|
|
+
|
|
|
+ var pi = m.Member as PropertyInfo;
|
|
|
+ var fi = m.Member as FieldInfo;
|
|
|
+ if (pi != null && pi.GetSetMethod(true) == null)
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (pi != null && pi.GetGetMethod(true) == null && m.KeepInstance)
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ var method = new DynamicMethod("dynamic_parser", null, new Type[] { typeof(IJsonReader), typeof(object) }, true);
|
|
|
+ var il = method.GetILGenerator();
|
|
|
+
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldarg_1);
|
|
|
+ il.Emit(OpCodes.Castclass, type);
|
|
|
+
|
|
|
+
|
|
|
+ if (m.KeepInstance)
|
|
|
+ {
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Dup);
|
|
|
+ if (pi != null)
|
|
|
+ il.Emit(OpCodes.Callvirt, pi.GetGetMethod(true));
|
|
|
+ else
|
|
|
+ il.Emit(OpCodes.Ldfld, fi);
|
|
|
+
|
|
|
+ var existingInstance = il.DeclareLocal(m.MemberType);
|
|
|
+ var lblExistingInstanceNull = il.DefineLabel();
|
|
|
+
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Dup);
|
|
|
+ il.Emit(OpCodes.Stloc, existingInstance);
|
|
|
+
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldnull);
|
|
|
+ il.Emit(OpCodes.Ceq);
|
|
|
+ il.Emit(OpCodes.Brtrue_S, lblExistingInstanceNull);
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(OpCodes.Ldloc, existingInstance);
|
|
|
+ il.Emit(OpCodes.Callvirt, typeof(IJsonReader).GetMethod("ParseInto", new Type[] { typeof(Object) }));
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Pop);
|
|
|
+ il.Emit(OpCodes.Ret);
|
|
|
+
|
|
|
+ il.MarkLabel(lblExistingInstanceNull);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ GenerateGetJsonValue(m, il);
|
|
|
+
|
|
|
+
|
|
|
+ if (pi != null)
|
|
|
+ il.Emit(OpCodes.Callvirt, pi.GetSetMethod(true));
|
|
|
+ if (fi != null)
|
|
|
+ il.Emit(OpCodes.Stfld, fi);
|
|
|
+
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ret);
|
|
|
+
|
|
|
+
|
|
|
+ setters.Add(m.JsonKey, (Action<IJsonReader, object>)method.CreateDelegate(typeof(Action<IJsonReader, object>)));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ Action<IJsonReader, object> parseInto = (reader, obj) =>
|
|
|
+ {
|
|
|
+
|
|
|
+ var loading = obj as IJsonLoading;
|
|
|
+ if (loading != null)
|
|
|
+ loading.OnJsonLoading(reader);
|
|
|
+
|
|
|
+
|
|
|
+ var lf = obj as IJsonLoadField;
|
|
|
+
|
|
|
+
|
|
|
+ reader.ParseDictionary(key =>
|
|
|
+ {
|
|
|
+
|
|
|
+ if (lf != null && lf.OnJsonField(reader, key))
|
|
|
+ return;
|
|
|
+
|
|
|
+
|
|
|
+ Action<IJsonReader, object> setter;
|
|
|
+ if (setters.TryGetValue(key, out setter))
|
|
|
+ {
|
|
|
+ setter(reader, obj);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ var loaded = obj as IJsonLoaded;
|
|
|
+ if (loaded != null)
|
|
|
+ loaded.OnJsonLoaded(reader);
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ RegisterIntoParser(type, parseInto);
|
|
|
+
|
|
|
+
|
|
|
+ return parseInto;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ static void RegisterIntoParser(Type type, Action<IJsonReader, object> parseInto)
|
|
|
+ {
|
|
|
+
|
|
|
+ var con = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[0], null);
|
|
|
+ if (con == null)
|
|
|
+ return;
|
|
|
+
|
|
|
+
|
|
|
+ var method = new DynamicMethod("dynamic_factory", typeof(object), new Type[] { typeof(IJsonReader), typeof(Action<IJsonReader, object>) }, true);
|
|
|
+ var il = method.GetILGenerator();
|
|
|
+
|
|
|
+
|
|
|
+ var locObj = il.DeclareLocal(typeof(object));
|
|
|
+ il.Emit(OpCodes.Newobj, con);
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Dup);
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Stloc, locObj);
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldarg_1);
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(OpCodes.Ldloc, locObj);
|
|
|
+ il.Emit(OpCodes.Callvirt, typeof(Action<IJsonReader, object>).GetMethod("Invoke"));
|
|
|
+ il.Emit(OpCodes.Ret);
|
|
|
+
|
|
|
+ var factory = (Func<IJsonReader, Action<IJsonReader, object>, object>)method.CreateDelegate(typeof(Func<IJsonReader, Action<IJsonReader, object>, object>));
|
|
|
+
|
|
|
+ Json.RegisterParser(type, (reader, type2) =>
|
|
|
+ {
|
|
|
+ return factory(reader, parseInto);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private static void GenerateGetJsonValue(JsonMemberInfo m, ILGenerator il)
|
|
|
+ {
|
|
|
+ Action<string> generateCallToHelper = helperName =>
|
|
|
+ {
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(OpCodes.Call, typeof(Emit).GetMethod(helperName, new Type[] { typeof(IJsonReader) }));
|
|
|
+
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(OpCodes.Callvirt, typeof(IJsonReader).GetMethod("NextToken", new Type[] { }));
|
|
|
+ };
|
|
|
+
|
|
|
+ Type[] numericTypes = new Type[] {
|
|
|
+ typeof(int), typeof(uint), typeof(long), typeof(ulong),
|
|
|
+ typeof(short), typeof(ushort), typeof(decimal),
|
|
|
+ typeof(byte), typeof(sbyte),
|
|
|
+ typeof(double), typeof(float)
|
|
|
+ };
|
|
|
+
|
|
|
+ if (m.MemberType == typeof(string))
|
|
|
+ {
|
|
|
+ generateCallToHelper("GetLiteralString");
|
|
|
+ }
|
|
|
+
|
|
|
+ else if (m.MemberType == typeof(bool))
|
|
|
+ {
|
|
|
+ generateCallToHelper("GetLiteralBool");
|
|
|
+ }
|
|
|
+
|
|
|
+ else if (m.MemberType == typeof(char))
|
|
|
+ {
|
|
|
+ generateCallToHelper("GetLiteralChar");
|
|
|
+ }
|
|
|
+
|
|
|
+ else if (numericTypes.Contains(m.MemberType))
|
|
|
+ {
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(OpCodes.Call, typeof(Emit).GetMethod("GetLiteralNumber", new Type[] { typeof(IJsonReader) }));
|
|
|
+
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Call, typeof(CultureInfo).GetProperty("InvariantCulture").GetGetMethod());
|
|
|
+ il.Emit(OpCodes.Call, m.MemberType.GetMethod("Parse", new Type[] { typeof(string), typeof(IFormatProvider) }));
|
|
|
+
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(OpCodes.Callvirt, typeof(IJsonReader).GetMethod("NextToken", new Type[] { }));
|
|
|
+ }
|
|
|
+
|
|
|
+ else
|
|
|
+ {
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(OpCodes.Ldtoken, m.MemberType);
|
|
|
+ il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) }));
|
|
|
+ il.Emit(OpCodes.Callvirt, typeof(IJsonReader).GetMethod("Parse", new Type[] { typeof(Type) }));
|
|
|
+ il.Emit(m.MemberType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, m.MemberType);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ [Obfuscation(Exclude = true)]
|
|
|
+ public static bool GetLiteralBool(IJsonReader r)
|
|
|
+ {
|
|
|
+ switch (r.GetLiteralKind())
|
|
|
+ {
|
|
|
+ case LiteralKind.True:
|
|
|
+ return true;
|
|
|
+
|
|
|
+ case LiteralKind.False:
|
|
|
+ return false;
|
|
|
+
|
|
|
+ default:
|
|
|
+ throw new InvalidDataException("expected a boolean value");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ [Obfuscation(Exclude = true)]
|
|
|
+ public static char GetLiteralChar(IJsonReader r)
|
|
|
+ {
|
|
|
+ if (r.GetLiteralKind() != LiteralKind.String)
|
|
|
+ throw new InvalidDataException("expected a single character string literal");
|
|
|
+ var str = r.GetLiteralString();
|
|
|
+ if (str == null || str.Length != 1)
|
|
|
+ throw new InvalidDataException("expected a single character string literal");
|
|
|
+
|
|
|
+ return str[0];
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ [Obfuscation(Exclude = true)]
|
|
|
+ public static string GetLiteralString(IJsonReader r)
|
|
|
+ {
|
|
|
+ switch (r.GetLiteralKind())
|
|
|
+ {
|
|
|
+ case LiteralKind.Null: return null;
|
|
|
+ case LiteralKind.String: return r.GetLiteralString();
|
|
|
+ }
|
|
|
+ throw new InvalidDataException("expected a string literal");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ [Obfuscation(Exclude = true)]
|
|
|
+ public static string GetLiteralNumber(IJsonReader r)
|
|
|
+ {
|
|
|
+ switch (r.GetLiteralKind())
|
|
|
+ {
|
|
|
+ case LiteralKind.SignedInteger:
|
|
|
+ case LiteralKind.UnsignedInteger:
|
|
|
+ case LiteralKind.FloatingPoint:
|
|
|
+ return r.GetLiteralString();
|
|
|
+ }
|
|
|
+ throw new InvalidDataException("expected a numeric literal");
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
#endif
|