using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection.Emit; using System.Reflection; using System.Collections; namespace fastJSON { internal struct Getters { public string Name; public Reflection.GenericGetter Getter; public Type propertyType; } internal sealed class Reflection { public readonly static Reflection Instance = new Reflection(); private Reflection() { } public bool ShowReadOnlyProperties = false; internal delegate object GenericSetter(object target, object value); internal delegate object GenericGetter(object obj); private delegate object CreateObject(); private SafeDictionary _tyname = new SafeDictionary(); private SafeDictionary _typecache = new SafeDictionary(); private SafeDictionary _constrcache = new SafeDictionary(); private SafeDictionary> _getterscache = new SafeDictionary>(); #region [ PROPERTY GET SET ] internal string GetTypeAssemblyName(Type t) { string val = ""; if (_tyname.TryGetValue(t, out val)) return val; else { string s = t.AssemblyQualifiedName; _tyname.Add(t, s); return s; } } internal Type GetTypeFromCache(string typename) { Type val = null; if (_typecache.TryGetValue(typename, out val)) return val; else { Type t = LoadType(typename); _typecache.Add(typename, t); return t; } } internal object FastCreateInstance(Type objtype) { try { CreateObject c = null; if (_constrcache.TryGetValue(objtype, out c)) { return c(); } else { if (objtype.IsClass) { DynamicMethod dynMethod = new DynamicMethod("_", objtype, null); ILGenerator ilGen = dynMethod.GetILGenerator(); ilGen.Emit(OpCodes.Newobj, objtype.GetConstructor(Type.EmptyTypes)); ilGen.Emit(OpCodes.Ret); c = (CreateObject)dynMethod.CreateDelegate(typeof(CreateObject)); _constrcache.Add(objtype, c); } else // structs { DynamicMethod dynMethod = new DynamicMethod("_", typeof(object), null); ILGenerator ilGen = dynMethod.GetILGenerator(); var lv = ilGen.DeclareLocal(objtype); ilGen.Emit(OpCodes.Ldloca_S, lv); ilGen.Emit(OpCodes.Initobj, objtype); ilGen.Emit(OpCodes.Ldloc_0); ilGen.Emit(OpCodes.Box, objtype); ilGen.Emit(OpCodes.Ret); c = (CreateObject)dynMethod.CreateDelegate(typeof(CreateObject)); _constrcache.Add(objtype, c); } return c(); } } catch (Exception exc) { throw new Exception(string.Format("Failed to fast create instance for type '{0}' from assemebly '{1}'", objtype.FullName, objtype.AssemblyQualifiedName), exc); } } internal static GenericSetter CreateSetField(Type type, FieldInfo fieldInfo) { Type[] arguments = new Type[2]; arguments[0] = arguments[1] = typeof(object); DynamicMethod dynamicSet = new DynamicMethod("_", typeof(object), arguments, type); ILGenerator il = dynamicSet.GetILGenerator(); if (!type.IsClass) // structs { var lv = il.DeclareLocal(type); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Unbox_Any, type); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Ldloca_S, lv); il.Emit(OpCodes.Ldarg_1); if (fieldInfo.FieldType.IsClass) il.Emit(OpCodes.Castclass, fieldInfo.FieldType); else il.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType); il.Emit(OpCodes.Stfld, fieldInfo); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Box, type); il.Emit(OpCodes.Ret); } else { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); if (fieldInfo.FieldType.IsValueType) il.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType); il.Emit(OpCodes.Stfld, fieldInfo); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ret); } return (GenericSetter)dynamicSet.CreateDelegate(typeof(GenericSetter)); } internal static GenericSetter CreateSetMethod(Type type, PropertyInfo propertyInfo) { MethodInfo setMethod = propertyInfo.GetSetMethod(); if (setMethod == null) return null; Type[] arguments = new Type[2]; arguments[0] = arguments[1] = typeof(object); DynamicMethod setter = new DynamicMethod("_", typeof(object), arguments); ILGenerator il = setter.GetILGenerator(); if (!type.IsClass) // structs { var lv = il.DeclareLocal(type); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Unbox_Any, type); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Ldloca_S, lv); il.Emit(OpCodes.Ldarg_1); if (propertyInfo.PropertyType.IsClass) il.Emit(OpCodes.Castclass, propertyInfo.PropertyType); else il.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType); il.EmitCall(OpCodes.Call, setMethod, null); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Box, type); } else { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Castclass, propertyInfo.DeclaringType); il.Emit(OpCodes.Ldarg_1); if (propertyInfo.PropertyType.IsClass) il.Emit(OpCodes.Castclass, propertyInfo.PropertyType); else il.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType); il.EmitCall(OpCodes.Callvirt, setMethod, null); il.Emit(OpCodes.Ldarg_0); } il.Emit(OpCodes.Ret); return (GenericSetter)setter.CreateDelegate(typeof(GenericSetter)); } internal static GenericGetter CreateGetField(Type type, FieldInfo fieldInfo) { DynamicMethod dynamicGet = new DynamicMethod("_", typeof(object), new Type[] { typeof(object) }, type); ILGenerator il = dynamicGet.GetILGenerator(); if (!type.IsClass) // structs { var lv = il.DeclareLocal(type); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Unbox_Any, type); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Ldloca_S, lv); il.Emit(OpCodes.Ldfld, fieldInfo); if (fieldInfo.FieldType.IsValueType) il.Emit(OpCodes.Box, fieldInfo.FieldType); } else { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, fieldInfo); if (fieldInfo.FieldType.IsValueType) il.Emit(OpCodes.Box, fieldInfo.FieldType); } il.Emit(OpCodes.Ret); return (GenericGetter)dynamicGet.CreateDelegate(typeof(GenericGetter)); } internal static GenericGetter CreateGetMethod(Type type, PropertyInfo propertyInfo) { MethodInfo getMethod = propertyInfo.GetGetMethod(); if (getMethod == null) return null; DynamicMethod getter = new DynamicMethod("_", typeof(object), new Type[] { typeof(object) }, type); ILGenerator il = getter.GetILGenerator(); if (!type.IsClass) // structs { var lv = il.DeclareLocal(type); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Unbox_Any, type); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Ldloca_S, lv); il.EmitCall(OpCodes.Call, getMethod, null); if (propertyInfo.PropertyType.IsValueType) il.Emit(OpCodes.Box, propertyInfo.PropertyType); } else { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Castclass, propertyInfo.DeclaringType); il.EmitCall(OpCodes.Callvirt, getMethod, null); if (propertyInfo.PropertyType.IsValueType) il.Emit(OpCodes.Box, propertyInfo.PropertyType); } il.Emit(OpCodes.Ret); return (GenericGetter)getter.CreateDelegate(typeof(GenericGetter)); } internal List GetGetters(Type type) { List val = null; if (_getterscache.TryGetValue(type, out val)) return val; PropertyInfo[] props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); List getters = new List(); foreach (PropertyInfo p in props) { if (!p.CanWrite && ShowReadOnlyProperties == false) continue; object[] att = p.GetCustomAttributes(typeof(System.Xml.Serialization.XmlIgnoreAttribute), false); if (att != null && att.Length > 0) continue; GenericGetter g = CreateGetMethod(type, p); if (g != null) { Getters gg = new Getters(); gg.Name = p.Name; gg.Getter = g; gg.propertyType = p.PropertyType; getters.Add(gg); } } FieldInfo[] fi = type.GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (var f in fi) { object[] att = f.GetCustomAttributes(typeof(System.Xml.Serialization.XmlIgnoreAttribute), false); if (att != null && att.Length > 0) continue; GenericGetter g = CreateGetField(type, f); if (g != null) { Getters gg = new Getters(); gg.Name = f.Name; gg.Getter = g; gg.propertyType = f.FieldType; getters.Add(gg); } } _getterscache.Add(type, getters); return getters; } private Type LoadType(string TypeName) { Type t = Type.GetType(TypeName); if (t == null && TypeName.Contains(",")) { // Split our assembly on first comma, which gives us namespaced typename, and assembly name / version / culture / public key info // E.g. this class' qualified name would be "fastJSON.Reflection, UnrealBuildTool, Version=4.0.0.0, Culture=neutral, PublicKeyToken=null". // This will be split into the type "jastJSON.Reflection" and the assembly "UnrealBuildTool, Version=4.0.0.0, Culture=neutral, PublicKeyToken=null". string[] TypeParts = TypeName.Split(new char[] { ',' }, 2, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToArray(); if (TypeParts.Length != 2) { return null; } Assembly Asm = null; try { Asm = Assembly.Load(TypeParts[1]); } catch (System.IO.FileNotFoundException) { Asm = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.FullName == TypeParts[1]); } if (Asm != null) { t = Asm.GetType(TypeParts[0]); } } return t; } #endregion } }