Search code examples
c#lambdareflection.emit

"Exception has been thrown by the target of an invocation." issue while implementing function with two params


I am trying to implement interface for dynamic generated class/method. The implementation is okay for method with one args(commented in code). But when method has two or more params it is throwing "Exception has been thrown by the target of an invocation". Unable to figureout what is wrong with two args? Any help would be appreciated. Below is my code:

using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Net.Http;
    using System.Reflection;
    using System.Reflection.Emit;
    using System.Security.Permissions;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Web.Http;
    using System.Web.Http.Controllers;

    namespace ConsoleApplication7
    {
        public class Foo
        {
            public string Bar(string m)
            {
                return m;
            }

        }
        public interface IFoo
        {
            string Barz(int i, int s);
            //string Barz(int i);// works good
        }

        public class Program
        {

            public string my(int w, int s)
            {
                return (s + w).ToString();
            }
            [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
            public void TestMethod()
            {

                var ab = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("TestAssembly"), AssemblyBuilderAccess.RunAndSave);

                var mb = ab.DefineDynamicModule("Test");
                var tb = mb.DefineType("Foo", typeof(Foo).Attributes, typeof(Foo));
                tb.AddInterfaceImplementation(typeof(IFoo));
                foreach (var imethod in typeof(IFoo).GetMethods())
                {
                    var method =
                      tb.DefineMethod
                      (
                        "@@" + imethod.Name,
                        MethodAttributes.Private | MethodAttributes.Static,
                        CallingConventions.Standard,
                        imethod.ReturnType,
                        imethod.GetParameters().Select(n => n.ParameterType).ToArray()
                      );

                    var thisParameter = Expression.Parameter(typeof(IFoo), "this");
                    var param = new ParameterExpression[] { Expression.Parameter(typeof(int)), Expression.Parameter(typeof(int)) };

                    var bodyExpression =
                      Expression.Lambda<Func<int,int, string>>(
                      Expression.Call(
                         Expression.New(typeof(Program)),
                         typeof(Program).GetMethod("my", new Type[] { typeof(int), typeof(int) }), param

                         ), param);
                    //var y = bodyExpression.Compile();//compiles good
                    //  var p = y.Invoke(200, "");//invocation is ok
                    bodyExpression.CompileToMethod(method);
                    var mp = imethod.GetParameters().Select(r => r.ParameterType).ToArray();
                    var stub =
                      tb.DefineMethod(imethod.Name, MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.Standard,
                       imethod.ReturnType, mp);
                    var il = stub.GetILGenerator();
                    il.Emit(OpCodes.Ldarg_0);
                    il.EmitCall(OpCodes.Call, method, null);
                    il.Emit(OpCodes.Ret);
                    tb.DefineMethodOverride(stub, imethod);
                }
                var type = tb.CreateType();
                ab.Save("test.dll");
                var obj = CreateAndInvoke(type, null, "Barz", null);

                Console.ReadLine();

            }
            public static object CreateAndInvoke(Type typeName, object[] constructorArgs, string methodName, object[] methodArgs)
            {
                Type type = typeName;
                object instance = Activator.CreateInstance(type);
                object[] a = new object[] { 900 ,0};
                MethodInfo method = type.GetMethod(methodName);
                return method.Invoke(instance, a);//issue over here
            }
            [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
            public static void Main(string[] args)
            {
                new Program().TestMethod(); 

            }


        }
    }

Solution

  • Unable to figure out what is wrong with two args? Any help would be appreciated.

    The code which does the code generation doesn't make any sense. It's written to generate a stub for an arbitrary method call, and then it passes a single argument to that method regardless of the arity of the method. That's completely wrong; the code is only correct for methods of one argument.

    The runtime will identify that problem during either verification or jitting, and give an invalid program exception, rather than running and misaligning the stack.