/// <summary> /// Create new Proxy Type (not instance) /// </summary> /// <typeparam name="TAbstract">Abstract or concrete definition of the proxy type</typeparam> /// <typeparam name="TInterceptor">Interceptor type</typeparam> /// <typeparam name="TConcrete">Concrete Type of the implementation</typeparam> /// <returns>Type of the new Proxy object</returns> public ProxyInfo <TAbstract> CreateProxyInfo <TAbstract, TConcrete, TInterceptor>(params object[] args) where TInterceptor : IInterceptor, new() where TConcrete : TAbstract { IProxyInfo result = null; void Create() { CreateBuilders(); var abstractType = typeof(TAbstract); var concreteType = typeof(TConcrete); var interceptorType = typeof(TInterceptor); var uniquePostfix = GetUniquePostfix <TAbstract, TConcrete, TInterceptor>(); if (uniquePostfix < 0) { uniquePostfix += int.MaxValue; } if (_cache.TryGetValue(uniquePostfix, out result) == false) { var type = _typeBuilder.Create(abstractType, concreteType, interceptorType, _moduleBuilder, $"_{uniquePostfix}"); var input = new ProxyMethodBuilderTransientParameters { TypeInfo = type, MethodCreationCounter = 0, PreInit = new List <IBeforeCollectInterceptorInformation>(_preInit), PreInvoke = new List <IBeforeInvokeInterceptor>(_preInvoke), PostInvoke = new List <IAfterInvokeInterceptor>(_postInvoke), }; foreach (var item in type.Methods) { _methodBuilder.Create(item, input); } var proxyType = type.ProxyType.CreateTypeInfo(); result = new ProxyInfo <TAbstract>( concreteType, abstractType, proxyType, uniquePostfix, proxyType.GetConstructors() ); _cache.Add(uniquePostfix, result); #if (!NETSTANDARD2_0) _builder.Save(DynamicAssemblyName + ".dll"); #endif } } LockExecuteRelease(Create); return((ProxyInfo <TAbstract>)result); }
public void Create(MethodInfo methodInfo, ProxyMethodBuilderTransientParameters transient) { var attributes = methodInfo.Attributes; if (transient.TypeInfo.ProxyType.IsInterface) { attributes = MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot; } else if (methodInfo.IsAbstract) { attributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot; } var parameters = methodInfo.GetParameters(); var method = transient.TypeInfo.ProxyType.DefineMethod(methodInfo.Name, attributes, methodInfo.CallingConvention, methodInfo.ReturnType, parameters.Select(a => a.ParameterType).ToArray()); MethodBuilder taskMethod = null; if (methodInfo.IsAbstract == false && (transient.TypeInfo.IsInterface == false || transient.TypeInfo.IsSealed)) { taskMethod = CreateBaseCallForTask(method, parameters, transient); } if (methodInfo.ContainsGenericParameters) { //TODO throw new NotImplementedException(); } var generator = method.GetILGenerator(); var listType = typeof(object[]); //object[] items; {0} generator.DeclareLocal(listType); //Task<object> task; {1} generator.DeclareLocal(typeof(Task <object>)); //InterceptorValues interceptorValues; {2} generator.DeclareLocal(InterceptorValuesType); foreach (var item in transient.PreInit) { item.Execute(transient.TypeInfo.ProxyType, transient.TypeInfo.Decorator, transient.TypeInfo.InterceptorInvoker, methodInfo, transient.PreInvoke, transient.PostInvoke); } generator.Emit(OpCodes.Ldc_I4, parameters.Length); generator.Emit(OpCodes.Newarr, typeof(object)); generator.Emit(OpCodes.Stloc_0); for (var i = 0; i < parameters.Length; i++) { generator.Emit(OpCodes.Ldloc_0); //items. generator.Emit(OpCodes.Ldc_I4, i); generator.Emit(OpCodes.Ldarg, i + 1); // method arg by index i + 1 since ldarg_0 == this generator.Emit(OpCodes.Stelem_Ref); // items[x] = X; } if (taskMethod == null) { generator.Emit(OpCodes.Newobj, NewObject); generator.Emit(OpCodes.Call, EmptyTaskCall); } else { // new Task<object>([proxyMethod], items); generator.Emit(OpCodes.Ldarg_0); //this generator.Emit(OpCodes.Ldftn, taskMethod); generator.Emit(OpCodes.Newobj, AnonymousFuncForTask); generator.Emit(OpCodes.Ldloc_0); // load items generator.Emit(OpCodes.Newobj, TaskWithResult); } //task = {see above} generator.Emit(OpCodes.Stloc_1); foreach (var item in transient.PreInvoke) { item.Execute(transient.TypeInfo.ProxyType, transient.TypeInfo.Decorator, transient.TypeInfo.InterceptorInvoker, methodInfo, transient.PostInvoke); } //interceptorValues = new InterceptorValues(this, [null|decorator], "[MethodName]", items, task); generator.Emit(OpCodes.Ldarg_0); if (transient.TypeInfo.Decorator != null) { generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldfld, transient.TypeInfo.Decorator); } else { generator.Emit(OpCodes.Ldnull); } generator.Emit(OpCodes.Ldstr, method.Name); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ldloc_1); generator.Emit(OpCodes.Newobj, InterceptorValuesConstructor); generator.Emit(OpCodes.Stloc_2); //proxy.invoke(...) generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldfld, transient.TypeInfo.InterceptorInvoker); generator.Emit(OpCodes.Ldloc_2); generator.Emit(OpCodes.Callvirt, InvokeInterceptor); foreach (var item in transient.PostInvoke) { item.Execute(transient.TypeInfo.ProxyType, transient.TypeInfo.Decorator, transient.TypeInfo.InterceptorInvoker, methodInfo); } if (method.ReturnType == typeof(void)) { generator.Emit(OpCodes.Pop); } else { generator.Emit(method.ReturnType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, method.ReturnType); } EmitDefaultValue(method.ReturnType, generator); generator.Emit(OpCodes.Ret); transient.MethodCreationCounter++; }
private MethodBuilder CreateBaseCallForTask(MethodInfo baseMethod, ParameterInfo[] parameters, ProxyMethodBuilderTransientParameters transient) { var result = transient.TypeInfo.ProxyType.DefineMethod(string.Concat(baseMethod.Name, "_Execute_", transient.MethodCreationCounter), MethodAttributes.Private | MethodAttributes.HideBySig, typeof(object), new[] { typeof(object) }); var generator = result.GetILGenerator(); var items = generator.DeclareLocal(typeof(object[])); if (parameters.Length > 0) { generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Castclass, items.LocalType); generator.Emit(OpCodes.Stloc_0); } var methodCall = OpCodes.Call; generator.Emit(OpCodes.Ldarg_0); //base. if (transient.TypeInfo.Decorator != null) { methodCall = OpCodes.Callvirt; generator.Emit(OpCodes.Ldfld, transient.TypeInfo.Decorator); //_decorator } generator.Emit(OpCodes.Ldloc_0); //items for (var i = 0; i < parameters.Length; i++) { generator.Emit(OpCodes.Ldc_I4, i); generator.Emit(OpCodes.Ldelem_Ref); if (parameters[i].ParameterType != typeof(object)) { var casting = parameters[i].ParameterType.GetTypeInfo().IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass; generator.Emit(casting, parameters[i].ParameterType); } } //(params ...) generator.Emit(methodCall, baseMethod); generator.Emit(OpCodes.Ret); return(result); }