0

I try to create a dynamic method in .NET which has an "in" parameter, but it throws an exception in the EmitCall line:

public struct Context
{
    public string MyString { get; set; }
}

public interface IHandler<T>
{
    void MyMethod(in Context context);
}

class MyMessage
{
}

class MyClass : IHandler<MyMessage>
{
    public void MyMethod(in Context context)
    {
    }
}

class ContextMethodInvoker
{
    private readonly InvokeHandler _invoker;

    private delegate void InvokeHandler(object handler, in Context context);

    public ContextMethodInvoker(MethodInfo methodInfo)
    {
        var dynamicMethod = new DynamicMethod(string.Empty,
            typeof(void), new[] { typeof(object), typeof(Context).MakeByRefType() });
        dynamicMethod.DefineParameter(1, ParameterAttributes.None, "handler");
        dynamicMethod.DefineParameter(2, ParameterAttributes.In, "context");

        var il = dynamicMethod.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldarg_1);

        il.EmitCall(OpCodes.Callvirt, methodInfo, null);
        il.Emit(OpCodes.Ret);

        _invoker = (InvokeHandler)dynamicMethod.CreateDelegate(typeof(InvokeHandler));
    }

    public void Invoke(object handler, in Context context)
    {
        _invoker.Invoke(handler, in context);
    }
}

And:

var messageHandlerType = typeof(IHandler<>);
var messageType = typeof(MyMessage);
var type = typeof(MyClass);

var interfaceType = messageHandlerType.MakeGenericType(messageType);

 
var contextMethod = new ContextMethodInvoker(
    type.GetInterfaceMap(interfaceType).TargetMethods.SingleOrDefault()
);

var tm = new Context
{
    MyString = "test"
};
contextMethod.Invoke(Activator.CreateInstance(type), tm);

What am I doing wrong? When I remove the "in" keywords and the MakeByRefType then it works.

2
  • I'm guess that ParameterAttributes.In have something to do with COM-interop. To emit same code as C#, you need to change type of parameter from Context to Context& (managed pointer to Context). For runtime there's no difference between in and out parameters, since they're just references. Compiler is able to differentiate between them by inspecting System.Runtime.CompilerServices.IsReadOnlyAttribute attached to parameter Commented Jan 27, 2023 at 5:30
  • After giving a closer look at actual code, the problem is that reference to Context should be loaded, not reference to where reference is hold. Insert ldind.ref after ldarg.1 Commented Jan 27, 2023 at 5:34

0

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.