-2

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(); 

            }


        }
    }
StartCoding
  • 394
  • 5
  • 16
  • That exception always has an inner exception you need to look at. That one describes the actual cause. – Joey Mar 26 '18 at 19:56
  • @joey {"Common Language Runtime detected an invalid program."} this is inner exception..unable to figure out what this means – StartCoding Mar 26 '18 at 19:57
  • 1
    Your program builds another program and runs it. The program that is built is an invalid program. Fix your code generator so that it generates legal code. – Eric Lippert Mar 26 '18 at 20:02
  • @ericlippert The program works well when the function has one args. Is this a compiler bug..or somewhat – StartCoding Mar 26 '18 at 20:03
  • 1
    How many arguments are you passing to the function? I see one. It requires two. Supply two. – Eric Lippert Mar 26 '18 at 20:04
  • @ericlippert for the sample above, I am passing two args. But when I try for function with one args, and modify program accrodingly..it works – StartCoding Mar 26 '18 at 20:05
  • You get the IL generator, you put one arg on the stack, and you execute the call. Does that call require two arguments? – Eric Lippert Mar 26 '18 at 20:06
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/167585/discussion-between-startcoding-and-eric-lippert). – StartCoding Mar 26 '18 at 20:06
  • @StartCoding: During your adventures in IL generation, you may wish to experiment with https://www.linqpad.net/ . One convenient feature it offers is the ability to instantly display the IL for any code snippet, with or without optimizations. – Brian Mar 27 '18 at 13:06
  • @Brian Thanks for suggestion. – StartCoding Mar 27 '18 at 13:47

1 Answers1

3

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.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067