|
@@ -558,13 +558,28 @@ namespace PetaJson
|
|
|
|
|
|
static Func<IJsonReader, Type, object> ResolveParser(Type type)
|
|
|
{
|
|
|
-
|
|
|
- Activator.CreateInstance(type);
|
|
|
-
|
|
|
-
|
|
|
- Func<IJsonReader, Type, object> parser;
|
|
|
- if (_parsers.TryGetValue(type, out parser))
|
|
|
- return parser;
|
|
|
+
|
|
|
+ var parseJson = ReflectionInfo.FindParseJson(type);
|
|
|
+ if (parseJson != null)
|
|
|
+ {
|
|
|
+ if (parseJson.GetParameters()[0].ParameterType == typeof(IJsonReader))
|
|
|
+ {
|
|
|
+ return (r, t) => parseJson.Invoke(null, new Object[] { r });
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return (r, t) =>
|
|
|
+ {
|
|
|
+ if (r.GetLiteralKind() == LiteralKind.String)
|
|
|
+ {
|
|
|
+ var o = parseJson.Invoke(null, new Object[] { r.GetLiteralString() });
|
|
|
+ r.NextToken();
|
|
|
+ return o;
|
|
|
+ }
|
|
|
+ throw new InvalidDataException(string.Format("Expected string literal for type {0}", type.FullName));
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
return (r, t) =>
|
|
|
{
|
|
@@ -984,6 +999,16 @@ namespace PetaJson
|
|
|
|
|
|
static Action<IJsonWriter, object> ResolveFormatter(Type type)
|
|
|
{
|
|
|
+
|
|
|
+ var formatJson = ReflectionInfo.FindFormatJson(type);
|
|
|
+ if (formatJson != null)
|
|
|
+ {
|
|
|
+ if (formatJson.ReturnType==typeof(void))
|
|
|
+ return (w, obj) => formatJson.Invoke(obj, new Object[] { w });
|
|
|
+ if (formatJson.ReturnType == typeof(string))
|
|
|
+ return (w, obj) => w.WriteStringLiteral((string)formatJson.Invoke(obj, new Object[] { }));
|
|
|
+ }
|
|
|
+
|
|
|
var ri = ReflectionInfo.GetReflectionInfo(type);
|
|
|
if (ri != null)
|
|
|
return ri.Write;
|
|
@@ -1308,6 +1333,38 @@ namespace PetaJson
|
|
|
|
|
|
static ThreadSafeCache<Type, ReflectionInfo> _cache = new ThreadSafeCache<Type, ReflectionInfo>();
|
|
|
|
|
|
+ public static MethodInfo FindFormatJson(Type type)
|
|
|
+ {
|
|
|
+ if (type.IsValueType)
|
|
|
+ {
|
|
|
+
|
|
|
+ var formatJson = type.GetMethod("FormatJson", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(IJsonWriter) }, null);
|
|
|
+ if (formatJson != null && formatJson.ReturnType == typeof(void))
|
|
|
+ return formatJson;
|
|
|
+
|
|
|
+
|
|
|
+ formatJson = type.GetMethod("FormatJson", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { }, null);
|
|
|
+ if (formatJson != null && formatJson.ReturnType == typeof(string))
|
|
|
+ return formatJson;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static MethodInfo FindParseJson(Type type)
|
|
|
+ {
|
|
|
+
|
|
|
+ var parseJson = type.GetMethod("ParseJson", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(IJsonReader) }, null);
|
|
|
+ if (parseJson != null && parseJson.ReturnType == type)
|
|
|
+ return parseJson;
|
|
|
+
|
|
|
+
|
|
|
+ parseJson = type.GetMethod("ParseJson", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(string) }, null);
|
|
|
+ if (parseJson != null && parseJson.ReturnType == type)
|
|
|
+ return parseJson;
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
public void Write(IJsonWriter w, object val)
|
|
|
{
|
|
@@ -1523,9 +1580,6 @@ namespace PetaJson
|
|
|
_lock.ExitReadLock();
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- TValue valNew = createIt();
|
|
|
-
|
|
|
|
|
|
_lock.EnterWriteLock();
|
|
|
try
|
|
@@ -1535,7 +1589,7 @@ namespace PetaJson
|
|
|
if (!_map.TryGetValue(key, out val))
|
|
|
{
|
|
|
|
|
|
- val = valNew;
|
|
|
+ val = createIt();
|
|
|
_map[key] = val;
|
|
|
}
|
|
|
return val;
|
|
@@ -2169,258 +2223,285 @@ namespace PetaJson
|
|
|
|
|
|
public static Action<IJsonWriter, object> MakeFormatter(Type type)
|
|
|
{
|
|
|
-
|
|
|
- var ri = ReflectionInfo.GetReflectionInfo(type);
|
|
|
- if (ri == null)
|
|
|
- return null;
|
|
|
+ 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 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 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 locInvariant = il.DeclareLocal(typeof(IFormatProvider));
|
|
|
+ il.Emit(OpCodes.Call, typeof(CultureInfo).GetProperty("InvariantCulture").GetGetMethod());
|
|
|
+ il.Emit(OpCodes.Stloc, locInvariant);
|
|
|
|
|
|
-
|
|
|
- var toStringTypes = new Type[] {
|
|
|
+
|
|
|
+ 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[] {
|
|
|
+
|
|
|
+ var otherSupportedTypes = new Type[] {
|
|
|
typeof(double), typeof(float), typeof(string), typeof(char)
|
|
|
};
|
|
|
|
|
|
-
|
|
|
- if (typeof(IJsonWriting).IsAssignableFrom(type))
|
|
|
- {
|
|
|
- if (type.IsValueType)
|
|
|
+
|
|
|
+ if (typeof(IJsonWriting).IsAssignableFrom(type))
|
|
|
{
|
|
|
- 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) }));
|
|
|
+ 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)
|
|
|
- {
|
|
|
-
|
|
|
- var pi = m.Member as PropertyInfo;
|
|
|
- if (pi != null && pi.GetGetMethod() == null)
|
|
|
+
|
|
|
+ foreach (var m in ri.Members)
|
|
|
{
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ldarg_0);
|
|
|
- il.Emit(OpCodes.Ldstr, m.JsonKey);
|
|
|
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteKeyNoEscaping", new Type[] { typeof(string) }));
|
|
|
-
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ldarg_0);
|
|
|
+
|
|
|
+ var pi = m.Member as PropertyInfo;
|
|
|
+ if (pi != null && pi.GetGetMethod() == null)
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
-
|
|
|
- var memberType = m.MemberType;
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
+ il.Emit(OpCodes.Ldstr, m.JsonKey);
|
|
|
+ il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteKeyNoEscaping", new Type[] { typeof(string) }));
|
|
|
|
|
|
-
|
|
|
- if (type.IsValueType)
|
|
|
- {
|
|
|
- il.Emit(OpCodes.Ldloca, locTypedObj);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- il.Emit(OpCodes.Ldloc, locTypedObj);
|
|
|
- }
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldarg_0);
|
|
|
|
|
|
-
|
|
|
- bool NeedValueAddress = (memberType.IsValueType && (toStringTypes.Contains(memberType) || otherSupportedTypes.Contains(memberType)));
|
|
|
- if (Nullable.GetUnderlyingType(memberType) != null)
|
|
|
- {
|
|
|
- NeedValueAddress = true;
|
|
|
- }
|
|
|
+
|
|
|
+ var memberType = m.MemberType;
|
|
|
|
|
|
-
|
|
|
- if (pi != null)
|
|
|
- {
|
|
|
-
|
|
|
+
|
|
|
if (type.IsValueType)
|
|
|
- il.Emit(OpCodes.Call, pi.GetGetMethod());
|
|
|
+ {
|
|
|
+ il.Emit(OpCodes.Ldloca, locTypedObj);
|
|
|
+ }
|
|
|
else
|
|
|
- il.Emit(OpCodes.Callvirt, pi.GetGetMethod());
|
|
|
+ {
|
|
|
+ il.Emit(OpCodes.Ldloc, locTypedObj);
|
|
|
+ }
|
|
|
|
|
|
-
|
|
|
- if (NeedValueAddress)
|
|
|
+
|
|
|
+ bool NeedValueAddress = (memberType.IsValueType && (toStringTypes.Contains(memberType) || otherSupportedTypes.Contains(memberType)));
|
|
|
+ if (Nullable.GetUnderlyingType(memberType) != null)
|
|
|
{
|
|
|
- var locTemp = il.DeclareLocal(memberType);
|
|
|
- il.Emit(OpCodes.Stloc, locTemp);
|
|
|
- il.Emit(OpCodes.Ldloca, locTemp);
|
|
|
+ NeedValueAddress = true;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
-
|
|
|
- var fi = m.Member as FieldInfo;
|
|
|
- if (fi != null)
|
|
|
- {
|
|
|
- if (NeedValueAddress)
|
|
|
+
|
|
|
+ if (pi != null)
|
|
|
{
|
|
|
- il.Emit(OpCodes.Ldflda, fi);
|
|
|
+
|
|
|
+ if (type.IsValueType)
|
|
|
+ il.Emit(OpCodes.Call, pi.GetGetMethod());
|
|
|
+ else
|
|
|
+ il.Emit(OpCodes.Callvirt, pi.GetGetMethod());
|
|
|
+
|
|
|
+
|
|
|
+ if (NeedValueAddress)
|
|
|
+ {
|
|
|
+ var locTemp = il.DeclareLocal(memberType);
|
|
|
+ il.Emit(OpCodes.Stloc, locTemp);
|
|
|
+ il.Emit(OpCodes.Ldloca, locTemp);
|
|
|
+ }
|
|
|
}
|
|
|
- else
|
|
|
+
|
|
|
+
|
|
|
+ var fi = m.Member as FieldInfo;
|
|
|
+ if (fi != null)
|
|
|
{
|
|
|
- il.Emit(OpCodes.Ldfld, fi);
|
|
|
+ if (NeedValueAddress)
|
|
|
+ {
|
|
|
+ il.Emit(OpCodes.Ldflda, fi);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ il.Emit(OpCodes.Ldfld, fi);
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- Label? lblFinished = null;
|
|
|
+ Label? lblFinished = null;
|
|
|
|
|
|
-
|
|
|
- var typeUnderlying = Nullable.GetUnderlyingType(memberType);
|
|
|
- if (typeUnderlying != null)
|
|
|
- {
|
|
|
-
|
|
|
- il.Emit(OpCodes.Dup);
|
|
|
+
|
|
|
+ var typeUnderlying = Nullable.GetUnderlyingType(memberType);
|
|
|
+ if (typeUnderlying != null)
|
|
|
+ {
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Dup);
|
|
|
|
|
|
-
|
|
|
- var lblHasValue = il.DefineLabel();
|
|
|
- lblFinished = il.DefineLabel();
|
|
|
+
|
|
|
+ var lblHasValue = il.DefineLabel();
|
|
|
+ lblFinished = il.DefineLabel();
|
|
|
|
|
|
-
|
|
|
- il.Emit(OpCodes.Call, memberType.GetProperty("HasValue").GetGetMethod());
|
|
|
- il.Emit(OpCodes.Brtrue, lblHasValue);
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Call, memberType.GetProperty("HasValue").GetGetMethod());
|
|
|
+ il.Emit(OpCodes.Brtrue, lblHasValue);
|
|
|
|
|
|
-
|
|
|
- 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.Value);
|
|
|
+
|
|
|
+ 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.Value);
|
|
|
|
|
|
-
|
|
|
- il.MarkLabel(lblHasValue);
|
|
|
- il.Emit(OpCodes.Call, memberType.GetProperty("Value").GetGetMethod());
|
|
|
+
|
|
|
+ il.MarkLabel(lblHasValue);
|
|
|
+ il.Emit(OpCodes.Call, memberType.GetProperty("Value").GetGetMethod());
|
|
|
|
|
|
-
|
|
|
- memberType = typeUnderlying;
|
|
|
- NeedValueAddress = (memberType.IsValueType && (toStringTypes.Contains(memberType) || otherSupportedTypes.Contains(memberType)));
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+ if (NeedValueAddress)
|
|
|
+ {
|
|
|
+ var locTemp = il.DeclareLocal(memberType);
|
|
|
+ il.Emit(OpCodes.Stloc, locTemp);
|
|
|
+ il.Emit(OpCodes.Ldloca, locTemp);
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
-
|
|
|
- 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) }));
|
|
|
- }
|
|
|
+
|
|
|
+ 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(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(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(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 == 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)
|
|
|
+ else
|
|
|
{
|
|
|
- il.Emit(OpCodes.Box, memberType);
|
|
|
+
|
|
|
+ if (memberType.IsValueType)
|
|
|
+ {
|
|
|
+ il.Emit(OpCodes.Box, memberType);
|
|
|
+ }
|
|
|
+ il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteValue", new Type[] { typeof(object) }));
|
|
|
}
|
|
|
- il.Emit(OpCodes.Callvirt, typeof(IJsonWriter).GetMethod("WriteValue", new Type[] { typeof(object) }));
|
|
|
- }
|
|
|
-
|
|
|
- if (lblFinished.HasValue)
|
|
|
- il.MarkLabel(lblFinished.Value);
|
|
|
- }
|
|
|
|
|
|
-
|
|
|
- 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]);
|
|
|
+ if (lblFinished.HasValue)
|
|
|
+ il.MarkLabel(lblFinished.Value);
|
|
|
}
|
|
|
- else
|
|
|
+
|
|
|
+
|
|
|
+ if (typeof(IJsonWritten).IsAssignableFrom(type))
|
|
|
{
|
|
|
- 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) }));
|
|
|
+ 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>));
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ret);
|
|
|
+ var impl = (Action<IJsonWriter, object>)method.CreateDelegate(typeof(Action<IJsonWriter, object>));
|
|
|
|
|
|
-
|
|
|
- return (w, obj) =>
|
|
|
- {
|
|
|
- w.WriteDictionary(() =>
|
|
|
+
|
|
|
+ return (w, obj) =>
|
|
|
{
|
|
|
- impl(w, obj);
|
|
|
- });
|
|
|
- };
|
|
|
-
|
|
|
+ w.WriteDictionary(() =>
|
|
|
+ {
|
|
|
+ impl(w, obj);
|
|
|
+ });
|
|
|
+ };
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|
|
@@ -2442,94 +2523,135 @@ namespace PetaJson
|
|
|
{
|
|
|
System.Diagnostics.Debug.Assert(type.IsValueType);
|
|
|
|
|
|
-
|
|
|
- var ri = ReflectionInfo.GetReflectionInfo(type);
|
|
|
- if (ri == null)
|
|
|
- return null;
|
|
|
+
|
|
|
+ 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();
|
|
|
|
|
|
-
|
|
|
- var setters = new Dictionary<string, Action<IJsonReader, object>>();
|
|
|
+ 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();
|
|
|
|
|
|
-
|
|
|
- var boxType = typeof(PseudoBox<>).MakeGenericType(type);
|
|
|
+ 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>));
|
|
|
|
|
|
-
|
|
|
- foreach (var m in ri.Members)
|
|
|
- {
|
|
|
-
|
|
|
- var pi = m.Member as PropertyInfo;
|
|
|
- var fi = m.Member as FieldInfo;
|
|
|
- if (pi != null && pi.GetSetMethod() == null)
|
|
|
- {
|
|
|
- continue;
|
|
|
+ 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 method = new DynamicMethod("dynamic_parser", null, new Type[] { typeof(IJsonReader), typeof(object) }, true);
|
|
|
- var il = method.GetILGenerator();
|
|
|
+
|
|
|
+ var setters = new Dictionary<string, Action<IJsonReader, object>>();
|
|
|
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ldarg_1);
|
|
|
- il.Emit(OpCodes.Castclass, boxType);
|
|
|
- il.Emit(OpCodes.Ldflda, boxType.GetField("value"));
|
|
|
+
|
|
|
+ var boxType = typeof(PseudoBox<>).MakeGenericType(type);
|
|
|
|
|
|
-
|
|
|
- GenerateGetJsonValue(m, il);
|
|
|
+
|
|
|
+ foreach (var m in ri.Members)
|
|
|
+ {
|
|
|
+
|
|
|
+ var pi = m.Member as PropertyInfo;
|
|
|
+ var fi = m.Member as FieldInfo;
|
|
|
+ if (pi != null && pi.GetSetMethod() == null)
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
-
|
|
|
- if (pi != null)
|
|
|
- il.Emit(OpCodes.Call, pi.GetSetMethod());
|
|
|
- if (fi != null)
|
|
|
- il.Emit(OpCodes.Stfld, fi);
|
|
|
+
|
|
|
+ var method = new DynamicMethod("dynamic_parser", null, new Type[] { typeof(IJsonReader), typeof(object) }, true);
|
|
|
+ var il = method.GetILGenerator();
|
|
|
|
|
|
-
|
|
|
- il.Emit(OpCodes.Ret);
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ldarg_1);
|
|
|
+ il.Emit(OpCodes.Castclass, boxType);
|
|
|
+ il.Emit(OpCodes.Ldflda, boxType.GetField("value"));
|
|
|
|
|
|
-
|
|
|
- setters.Add(m.JsonKey, (Action<IJsonReader, object>)method.CreateDelegate(typeof(Action<IJsonReader, object>)));
|
|
|
- }
|
|
|
+
|
|
|
+ GenerateGetJsonValue(m, il);
|
|
|
|
|
|
-
|
|
|
-
|
|
|
- Action<object, IJsonReader> invokeLoading = MakeInterfaceCall(type, typeof(IJsonLoading));
|
|
|
- Action<object, IJsonReader> invokeLoaded = MakeInterfaceCall(type, typeof(IJsonLoaded));
|
|
|
- Func<object, IJsonReader, string, bool> invokeField = MakeLoadFieldCall(type);
|
|
|
+
|
|
|
+ if (pi != null)
|
|
|
+ il.Emit(OpCodes.Call, pi.GetSetMethod());
|
|
|
+ if (fi != null)
|
|
|
+ il.Emit(OpCodes.Stfld, fi);
|
|
|
|
|
|
-
|
|
|
- Func<IJsonReader, Type, object> parser = (reader, Type) =>
|
|
|
- {
|
|
|
-
|
|
|
- var box = Activator.CreateInstance(boxType);
|
|
|
+
|
|
|
+ il.Emit(OpCodes.Ret);
|
|
|
|
|
|
-
|
|
|
- if (invokeLoading != null)
|
|
|
- invokeLoading(box, reader);
|
|
|
+
|
|
|
+ setters.Add(m.JsonKey, (Action<IJsonReader, object>)method.CreateDelegate(typeof(Action<IJsonReader, object>)));
|
|
|
+ }
|
|
|
|
|
|
-
|
|
|
- reader.ParseDictionary(key =>
|
|
|
+
|
|
|
+
|
|
|
+ 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) =>
|
|
|
{
|
|
|
-
|
|
|
- if (invokeField != null && invokeField(box, reader, key))
|
|
|
- return;
|
|
|
+
|
|
|
+ var box = Activator.CreateInstance(boxType);
|
|
|
|
|
|
-
|
|
|
- Action<IJsonReader, object> setter;
|
|
|
- if (setters.TryGetValue(key, out setter))
|
|
|
+
|
|
|
+ if (invokeLoading != null)
|
|
|
+ invokeLoading(box, reader);
|
|
|
+
|
|
|
+
|
|
|
+ reader.ParseDictionary(key =>
|
|
|
{
|
|
|
- setter(reader, box);
|
|
|
- }
|
|
|
- });
|
|
|
+
|
|
|
+ if (invokeField != null && invokeField(box, reader, key))
|
|
|
+ return;
|
|
|
|
|
|
-
|
|
|
- if (invokeLoaded != null)
|
|
|
- invokeLoaded(box, reader);
|
|
|
+
|
|
|
+ Action<IJsonReader, object> setter;
|
|
|
+ if (setters.TryGetValue(key, out setter))
|
|
|
+ {
|
|
|
+ setter(reader, box);
|
|
|
+ }
|
|
|
+ });
|
|
|
|
|
|
-
|
|
|
- return ((IPseudoBox)box).GetValue();
|
|
|
- };
|
|
|
+
|
|
|
+ if (invokeLoaded != null)
|
|
|
+ invokeLoaded(box, reader);
|
|
|
|
|
|
-
|
|
|
- return parser;
|
|
|
+
|
|
|
+ return ((IPseudoBox)box).GetValue();
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ return parser;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|