/// <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);
        }
Beispiel #2
0
        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++;
        }
Beispiel #3
0
        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);
        }