#if !SILVERLIGHT && !PocketPC using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Resources; using System.Text; using System.Threading; using System.Globalization; namespace Newtonsoft.Json.Utilities { internal class DynamicWrapperBase { internal protected object UnderlyingObject; } internal static class DynamicWrapper { private static readonly object _lock = new object(); private static readonly WrapperDictionary _wrapperDictionary = new WrapperDictionary(); private static ModuleBuilder _moduleBuilder; private static ModuleBuilder ModuleBuilder { get { Init(); return _moduleBuilder; } } private static void Init() { if (_moduleBuilder == null) { lock (_lock) { if (_moduleBuilder == null) { AssemblyName assemblyName = new AssemblyName("Newtonsoft.Json.Dynamic"); assemblyName.KeyPair = new StrongNameKeyPair(GetStrongKey()); AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); _moduleBuilder = assembly.DefineDynamicModule("Newtonsoft.Json.DynamicModule", false); } } } } private static byte[] GetStrongKey() { using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Newtonsoft.Json.Dynamic.snk")) { if (stream == null) throw new MissingManifestResourceException("Should have a Newtonsoft.Json.Dynamic.snk as an embedded resource."); int length = (int)stream.Length; byte[] buffer = new byte[length]; stream.Read(buffer, 0, length); return buffer; } } public static Type GetWrapper(Type interfaceType, Type realObjectType) { Type wrapperType = _wrapperDictionary.GetType(interfaceType, realObjectType); if (wrapperType == null) { wrapperType = GenerateWrapperType(interfaceType, realObjectType); _wrapperDictionary.SetType(interfaceType, realObjectType, wrapperType); } return wrapperType; } public static object GetUnderlyingObject(object wrapper) { DynamicWrapperBase wrapperBase = wrapper as DynamicWrapperBase; if (wrapperBase == null) throw new ArgumentException("Object is not a wrapper.", "wrapper"); return wrapperBase.UnderlyingObject; } private static Type GenerateWrapperType(Type interfaceType, Type underlyingType) { TypeBuilder wrapperBuilder = ModuleBuilder.DefineType( "{0}_{1}_Wrapper".FormatWith(CultureInfo.InvariantCulture, interfaceType.Name, underlyingType.Name), TypeAttributes.NotPublic | TypeAttributes.Sealed, typeof(DynamicWrapperBase), new[] { interfaceType }); WrapperMethodBuilder wrapperMethod = new WrapperMethodBuilder(underlyingType, wrapperBuilder); foreach (MethodInfo method in interfaceType.AllMethods()) { wrapperMethod.Generate(method); } return wrapperBuilder.CreateType(); } public static T CreateWrapper(object realObject) where T : class { var dynamicType = GetWrapper(typeof(T), realObject.GetType()); var dynamicWrapper = (DynamicWrapperBase)Activator.CreateInstance(dynamicType); dynamicWrapper.UnderlyingObject = realObject; return dynamicWrapper as T; } } internal class WrapperMethodBuilder { private readonly Type _realObjectType; private readonly TypeBuilder _wrapperBuilder; public WrapperMethodBuilder(Type realObjectType, TypeBuilder proxyBuilder) { _realObjectType = realObjectType; _wrapperBuilder = proxyBuilder; } public void Generate(MethodInfo newMethod) { if (newMethod.IsGenericMethod) newMethod = newMethod.GetGenericMethodDefinition(); FieldInfo srcField = typeof(DynamicWrapperBase).GetField("UnderlyingObject", BindingFlags.Instance | BindingFlags.NonPublic); var parameters = newMethod.GetParameters(); var parameterTypes = parameters.Select(parameter => parameter.ParameterType).ToArray(); MethodBuilder methodBuilder = _wrapperBuilder.DefineMethod( newMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual, newMethod.ReturnType, parameterTypes); if (newMethod.IsGenericMethod) { methodBuilder.DefineGenericParameters( newMethod.GetGenericArguments().Select(arg => arg.Name).ToArray()); } ILGenerator ilGenerator = methodBuilder.GetILGenerator(); LoadUnderlyingObject(ilGenerator, srcField); PushParameters(parameters, ilGenerator); ExecuteMethod(newMethod, parameterTypes, ilGenerator); Return(ilGenerator); } private static void Return(ILGenerator ilGenerator) { ilGenerator.Emit(OpCodes.Ret); } private void ExecuteMethod(MethodBase newMethod, Type[] parameterTypes, ILGenerator ilGenerator) { MethodInfo srcMethod = GetMethod(newMethod, parameterTypes); if (srcMethod == null) throw new MissingMethodException("Unable to find method " + newMethod.Name + " on " + _realObjectType.FullName); ilGenerator.Emit(OpCodes.Call, srcMethod); } private MethodInfo GetMethod(MethodBase realMethod, Type[] parameterTypes) { if (realMethod.IsGenericMethod) return _realObjectType.GetGenericMethod(realMethod.Name, parameterTypes); return _realObjectType.GetMethod(realMethod.Name, parameterTypes); } private static void PushParameters(ICollection parameters, ILGenerator ilGenerator) { for (int i = 1; i < parameters.Count + 1; i++) ilGenerator.Emit(OpCodes.Ldarg, i); } private static void LoadUnderlyingObject(ILGenerator ilGenerator, FieldInfo srcField) { ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Ldfld, srcField); } } internal class WrapperDictionary { private readonly Dictionary _wrapperTypes = new Dictionary(); private static string GenerateKey(Type interfaceType, Type realObjectType) { return interfaceType.Name + "_" + realObjectType.Name; } public Type GetType(Type interfaceType, Type realObjectType) { string key = GenerateKey(interfaceType, realObjectType); if (_wrapperTypes.ContainsKey(key)) return _wrapperTypes[key]; return null; } public void SetType(Type interfaceType, Type realObjectType, Type wrapperType) { string key = GenerateKey(interfaceType, realObjectType); if (_wrapperTypes.ContainsKey(key)) _wrapperTypes[key] = wrapperType; else _wrapperTypes.Add(key, wrapperType); } } internal static class TypeExtensions { public static MethodInfo GetGenericMethod(this Type type, string name, params Type[] parameterTypes) { var methods = type.GetMethods().Where(method => method.Name == name); foreach (var method in methods) { if (method.HasParameters(parameterTypes)) return method; } return null; } public static bool HasParameters(this MethodInfo method, params Type[] parameterTypes) { var methodParameters = method.GetParameters().Select(parameter => parameter.ParameterType).ToArray(); if (methodParameters.Length != parameterTypes.Length) return false; for (int i = 0; i < methodParameters.Length; i++) if (methodParameters[i].ToString() != parameterTypes[i].ToString()) return false; return true; } public static IEnumerable AllInterfaces(this Type target) { foreach (var IF in target.GetInterfaces()) { yield return IF; foreach (var childIF in IF.AllInterfaces()) { yield return childIF; } } } public static IEnumerable AllMethods(this Type target) { var allTypes = target.AllInterfaces().ToList(); allTypes.Add(target); return from type in allTypes from method in type.GetMethods() select method; } } } #endif