using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; namespace ARMeilleure.Translation { static class DelegateHelper { private const string DelegateTypesAssemblyName = "JitDelegateTypes"; private static readonly ModuleBuilder _modBuilder; private static readonly Dictionary<string, Type> _delegateTypesCache; static DelegateHelper() { AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(DelegateTypesAssemblyName), AssemblyBuilderAccess.Run); _modBuilder = asmBuilder.DefineDynamicModule(DelegateTypesAssemblyName); _delegateTypesCache = new Dictionary<string, Type>(); } public static Delegate GetDelegate(MethodInfo info) { if (info == null) { throw new ArgumentNullException(nameof(info)); } Type[] parameters = info.GetParameters().Select(pI => pI.ParameterType).ToArray(); Type returnType = info.ReturnType; Type delegateType = GetDelegateType(parameters, returnType); return Delegate.CreateDelegate(delegateType, info); } private static Type GetDelegateType(Type[] parameters, Type returnType) { string key = GetFunctionSignatureKey(parameters, returnType); if (!_delegateTypesCache.TryGetValue(key, out Type delegateType)) { delegateType = MakeDelegateType(parameters, returnType, key); _delegateTypesCache.TryAdd(key, delegateType); } return delegateType; } private static string GetFunctionSignatureKey(Type[] parameters, Type returnType) { string sig = GetTypeName(returnType); foreach (Type type in parameters) { sig += '_' + GetTypeName(type); } return sig; } private static string GetTypeName(Type type) { return type.FullName.Replace(".", string.Empty); } private const MethodAttributes CtorAttributes = MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public; private const TypeAttributes DelegateTypeAttributes = TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass; private const MethodImplAttributes ImplAttributes = MethodImplAttributes.Runtime | MethodImplAttributes.Managed; private const MethodAttributes InvokeAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual; private static readonly Type[] _delegateCtorSignature = { typeof(object), typeof(IntPtr) }; private static Type MakeDelegateType(Type[] parameters, Type returnType, string name) { TypeBuilder builder = _modBuilder.DefineType(name, DelegateTypeAttributes, typeof(MulticastDelegate)); builder.DefineConstructor(CtorAttributes, CallingConventions.Standard, _delegateCtorSignature).SetImplementationFlags(ImplAttributes); builder.DefineMethod("Invoke", InvokeAttributes, returnType, parameters).SetImplementationFlags(ImplAttributes); return builder.CreateTypeInfo(); } } }