3

If I create a DynamicMethod from inside a class method how can I call another method of my class from the DynamicMethod Delegate? I need somehow to capture the this reference in the DynamicMethod code. But I can't find an overladed version of ILGenerator.Emit which takes an object as parameter.

The code is so far:

    void CallOpc(string name, object[] inp, object[] outp)
    {
        //...
    }

    public D CreateDelegate<D>(string opcName) where D : class
    {
        var dType = typeof(D);
        var invoke = dType.GetMethod("Invoke");

        var parameters = invoke.GetParameters();
        var paramTypes = parameters.Select(p => p.ParameterType).ToArray();
        DynamicMethod dm = new DynamicMethod(
            opcName,
            invoke.ReturnType,
            paramTypes,
            true);

        var inp = parameters.Where(p => !p.IsOut).Select(p => p.ParameterType).ToList();
        var outp = parameters.Where(p => p.IsOut).Select(p => p.ParameterType).ToList();
        if (invoke.ReturnType != typeof(void))
        {
            outp.Insert(0, invoke.ReturnType);
        }
        ILGenerator il = dm.GetILGenerator();

        LocalBuilder invar = il.DeclareLocal(typeof(object[]));
        LocalBuilder outvar = il.DeclareLocal(typeof(object[]));

        il.Emit(OpCodes.Ldc_I4, inp.Count);
        il.Emit(OpCodes.Newarr, typeof(object));
        il.Emit(OpCodes.Stloc, invar);

        for (int i = 0; i < inp.Count; i++)
        {
            il.Emit(OpCodes.Ldloc, invar);
            il.Emit(OpCodes.Ldc_I4, i);
            int j = Array.IndexOf(paramTypes, inp[i]);
            il.Emit(OpCodes.Ldarg, j);
            if (!inp[i].IsClass)
            {
                il.Emit(OpCodes.Box, inp[i]);
            }
            il.Emit(OpCodes.Stelem_Ref);
        }

        il.Emit(OpCodes.Ldc_I4, outp.Count);
        il.Emit(OpCodes.Newarr, typeof(object));
        il.Emit(OpCodes.Stloc, outvar);

        il.Emit(OpCodes.Ldarg_0);   // <- push this on the evaluation stack ???
        il.Emit(OpCodes.Ldstr, opcName);
        il.Emit(OpCodes.Ldloc, invar);
        il.Emit(OpCodes.Ldloc, outvar);
        MethodInfo callOpcMeth = GetType().GetMethod("CallOpc", BindingFlags.Instance | BindingFlags.NonPublic);
        il.Emit(OpCodes.Callvirt, callOpcMeth);


        for (int o = 0; o < outp.Count; o++)
        {
            // TODO: handle out params and return value
        }
        il.Emit(OpCodes.Ret);
        return (D)(object)dm.CreateDelegate(dType);
    }

My problem is the line marked with ???

5
  • 1
    How can code have a reference to an object? it can't. You need to pass it as a parameter (at runtime). Commented Dec 15, 2015 at 21:15
  • Ok, I have a Communication Channel to a remote System which handles Method calls by 2 arrays of object; one for in and one for out values and the return value. For better type safety I want to provide delegates with the right signature. Therefore I'd like create dynamic delegates for diffrent method signatures. The delegate code will than create the 2 object[] arrays, puts the arguments in the one array, call the internal method and copies the return and out parameters out of the other array and returns. Commented Dec 15, 2015 at 21:22
  • Since we don't know the issue behind the scenes you're trying to fix or provide a solution I'll just add here a comment: who knows if using expression trees the same issue could be solved without using reflection emit directly.. Commented Dec 15, 2015 at 21:40
  • Have added the complete code now. Commented Dec 15, 2015 at 21:52
  • Can't you use expression trees? They support this right away. Commented Dec 15, 2015 at 23:07

1 Answer 1

4

How to reference the this pointer from a DynamicMethod?

At low level, methods do not have a specific this pointer, instead the first argument of the method is used as this.

To reference the this pointer, here is what you have to do:

  • Prepend a new argument to your argument list, matching the type you want to use as this
  • Use that argument as this wherever you want
  • Create the delegate using DynamicMethod.CreateDelegate(Type,Object) to bind the first parameter to your object: return (D)(object)dm.CreateDelegate(dType, this);

Note that creating dynamic methods is expensive. If you generate the same DynamicMethod for multiple instances, you should cache the method itself, and create delegates using the cached method, but with different target parameter.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you; now it works like intended. And yes I will cache the created delegates.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.