Example #1
0
        private static void GenerateCallerMethod(GeneratorContext context)
        {
            if (context.Parameters.Length != 0)
            {
                return;
            }

            MethodBase baseMethod;
            Type       returnType;

            if (context.CallerType == CallerType.Ctor)
            {
                baseMethod = context.Constructor;
                returnType = null;
            }
            else
            {
                baseMethod = context.Method;
                returnType = context.Method.ReturnType;
            }

            var method = context.TypeBuilder.DefineMethod(
                $"<{baseMethod.Name}>_{context.Token}",
                MethodAttributes.Private | MethodAttributes.HideBySig,
                CallingConventions.HasThis | CallingConventions.Standard,
                returnType,
                context.Parameters.Select(x => x.Type).ToArray()
                );

            method.SetMethodParameters(baseMethod, baseMethod.GetParameters());

            var generator = method.GetILGenerator();

            generator.Emit(OpCodes.Ldarg_0);

            if (context.Parameters.Length > 0)
            {
                for (var i = 1; i <= context.Parameters.Length; i++)
                {
                    generator.Emit(OpCodes.Ldarg_S, i);
                }
            }

            if (context.InterfaceMethod == null)
            {
                if (context.CallerType == CallerType.Ctor)
                {
                    generator.Emit(OpCodes.Call, context.Constructor);
                }
                else
                {
                    generator.Emit(OpCodes.Call, context.Method);
                }
            }
            else
            {
                generator.Emit(OpCodes.Ldfld, context.Interface);
                generator.Emit(OpCodes.Callvirt, context.InterfaceMethod);
            }

            generator.Emit(OpCodes.Ret);
            context.CallerMethod = method;
        }
Example #2
0
        private static void MethodBodSetp4(GeneratorContext context, ILGenerator generator)
        {
            var callerType = context.CallerType;
            var parameters = context.Parameters;

            if (parameters.Length > 0)
            {
                // Action or Func<T> call = () => base.Method(xx);
                generator.Emit(OpCodes.Ldloc_0);
                generator.Emit(OpCodes.Ldftn, context.DisplayMethod);
                generator.Emit(OpCodes.Newobj, context.CallType.GetConstructors()[0]);
                generator.Emit(OpCodes.Stloc_2);

                // T result = this._caller.Call(this, call, parameters);
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Ldfld, context.Caller);
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Ldloc_2);
                generator.Emit(OpCodes.Ldloc_1);
                generator.Emit(OpCodes.Callvirt, context.Caller.FieldType.GetMethod(
                                   "Call",
                                   BindingFlags.Public | BindingFlags.Instance
                                   ));

                for (var i = 1; i <= parameters.Length; i++)
                {
                    var parameter = parameters[i - 1];
                    if (parameter.IsOut || parameter.IsRef)
                    {
                        var field = context.DisplayFields[i];
                        generator.Emit(OpCodes.Ldarg_S, i);
                        generator.Emit(OpCodes.Ldloc_0);
                        generator.Emit(OpCodes.Ldfld, field);
                        if (field.FieldType.IsValueType)
                        {
                            generator.Emit(OpCodes.Stobj, field.FieldType);
                        }
                        else
                        {
                            generator.Emit(OpCodes.Stind_Ref);
                        }
                    }
                }
            }
            else
            {
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Ldftn, context.CallerMethod);
                generator.Emit(OpCodes.Newobj, context.CallType.GetConstructors()[0]);
                generator.Emit(OpCodes.Stloc_0);

                // this._caller.Call(this, call, null);
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Ldfld, context.Caller);
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Ldloc_0);
                generator.Emit(OpCodes.Ldnull);
                generator.Emit(OpCodes.Callvirt, context.Caller.FieldType.GetMethod(
                                   "Call",
                                   BindingFlags.Public | BindingFlags.Instance
                                   ));
            }

            generator.Emit(OpCodes.Ret);
        }
Example #3
0
        private static GeneratorContext GetMethodContext(
            MethodBase builder,
            MethodBase proxyMethod,
            MethodInfo interfaceMethod,
            ILGenerator generator,
            GeneratorTypeContext typeContext,
            ParameterInfo[] parameters
            )
        {
            var context = new GeneratorContext(typeContext)
            {
                Generator       = generator,
                InterfaceMethod = interfaceMethod,
                Parameters      = proxyMethod.GetParameters().Select(x => new ParamInfo(x)).ToArray()
            };

            Type fieldType;

            if (proxyMethod is MethodInfo meth)
            {
                context.Method = meth;
                var returnType = meth.ReturnType;
                if (returnType.IsByRef)
                {
                    context.ReturnType = returnType;
                }
                else
                {
                    if (returnType == typeof(void))
                    {
                        context.ReturnType = returnType;
                        context.CallerType = CallerType.Void;
                        fieldType          = typeof(VoidCaller);
                    }
                    else if (!meth.IsDefined(typeof(StateMachineAttribute)))
                    {
                        context.ReturnType = returnType;
                        context.CallerType = CallerType.Return;
                        fieldType          = typeof(ReturnCaller <>).MakeGenericType(returnType);
                    }
                    else if (returnType == typeof(Task))
                    {
                        context.ReturnType = null;
                        context.CallerType = CallerType.Task;
                        fieldType          = typeof(TaskCaller);
                    }
                    else if (returnType.IsGenericType)
                    {
                        var type = returnType.GetGenericTypeDefinition();
                        context.ReturnType = returnType.GetGenericArguments()[0];
                        if (type == typeof(Task <>))
                        {
                            context.CallerType = CallerType.TaskOfT;
                            fieldType          = typeof(TaskCaller <>).MakeGenericType(context.ReturnType);
                        }
                        else if (type == typeof(ValueTask <>))
                        {
                            context.CallerType = CallerType.ValueTaskOfT;
                            fieldType          = typeof(ValueTaskCaller <>).MakeGenericType(context.ReturnType);
                        }
                        else
                        {
                            throw new InvalidOperationException("function return value error!");
                        }
                    }
                    else
                    {
                        throw new InvalidOperationException("function return value error!");
                    }

                    context.Caller        = context.TypeBuilder.DefineField($"<>_caller{context.Token}", fieldType, FieldAttributes.Private);
                    context.MethodBuilder = (MethodBuilder)builder;
                }
            }
            else if (proxyMethod is ConstructorInfo ctor)
            {
                context.Constructor        = ctor;
                context.ReturnType         = null;
                context.CallerType         = CallerType.Ctor;
                context.Caller             = context.TypeBuilder.DefineField($"<>_caller{context.Token}", typeof(VoidCaller), FieldAttributes.Private);
                context.ConstructorBuilder = (ConstructorBuilder)builder;
            }

            return(context);
        }
Example #4
0
        private static void MethodBodSetp3(GeneratorContext context, ILGenerator generator)
        {
            if (context.Parameters.Length == 0)
            {
                return;
            }

            var parameters    = context.Parameters;
            var displayFields = context.DisplayFields;

            generator.Emit(OpCodes.Ldc_I4, parameters.Length);
            generator.Emit(OpCodes.Newarr, typeof(object));
            generator.Emit(OpCodes.Stloc_1);

            for (var i = 1; i <= parameters.Length; i++)
            {
                var parameter    = parameters[i - 1];
                var displayField = displayFields[i];

                generator.Emit(OpCodes.Ldloc_0);
                if (parameter.IsOut)
                {
                    if (displayField.FieldType.IsValueType)
                    {
                        generator.Emit(OpCodes.Ldflda, displayField);
                        generator.Emit(OpCodes.Initobj, displayField.FieldType);
                    }
                    else
                    {
                        generator.Emit(OpCodes.Ldnull);
                        generator.Emit(OpCodes.Stfld, displayField);
                    }
                }
                else if (parameter.IsRef)
                {
                    generator.Emit(OpCodes.Ldarg_S, i);
                    if (displayField.FieldType.IsValueType)
                    {
                        generator.Emit(OpCodes.Ldobj, displayField.FieldType);
                    }
                    else
                    {
                        generator.Emit(OpCodes.Ldind_Ref);
                    }

                    generator.Emit(OpCodes.Stfld, displayField);
                }
                else
                {
                    generator.Emit(OpCodes.Ldarg_S, i);
                    generator.Emit(OpCodes.Stfld, displayField);
                }

                generator.Emit(OpCodes.Ldloc_1);
                generator.Emit(OpCodes.Ldc_I4, i - 1);
                if (parameter.IsOut)
                {
                    generator.Emit(OpCodes.Ldloc_0);
                    generator.Emit(OpCodes.Ldfld, displayField);
                    if (displayField.FieldType.IsValueType)
                    {
                        generator.Emit(OpCodes.Box, displayField.FieldType);
                    }
                }
                else if (parameter.IsRef)
                {
                    generator.Emit(OpCodes.Ldarg_S, i);
                    if (displayField.FieldType.IsValueType)
                    {
                        generator.Emit(OpCodes.Ldobj, displayField.FieldType);
                        generator.Emit(OpCodes.Box, displayField.FieldType);
                    }
                    else
                    {
                        generator.Emit(OpCodes.Ldind_Ref);
                    }
                }
                else
                {
                    generator.Emit(OpCodes.Ldloc_0);
                    generator.Emit(OpCodes.Ldfld, displayField);
                    if (displayField.FieldType.IsValueType)
                    {
                        generator.Emit(OpCodes.Box, displayField.FieldType);
                    }
                }

                generator.Emit(OpCodes.Stelem_Ref);
            }
        }