How can I emit a dynamic method returning a ref?

Viewed 683

I'm navigating the ins and outs of ref returns, and am having trouble emitting a dynamic method which returns by ref.

Handcrafted lambdas and existing methods work as expected:

class Widget
{
    public int Length;
}
delegate ref int WidgetMeasurer(Widget w);

WidgetMeasurer GetMeasurerA()
{
    return w => ref w.Length;
}

static ref int MeasureWidget(Widget w) => ref w.Length;
WidgetMeasurer GetMeasurerB()
{
    return MeasureWidget;
}

But emitting a dynamic method fails. Note: I'm using Sigil here. Apologies, I'm less familiar with System.Reflection.Emit.

WidgetMeasurer GetMeasurerC()
{
    FieldInfo lengthField = typeof(Widget).GetField(nameof(Widget.Length));
    var emitter = Emit<WidgetMeasurer>.NewDynamicMethod()
        .LoadArgument(0)
        .LoadFieldAddress(lengthField)
        .Return();
    return emitter.CreateDelegate();
}

This fails at NewDynamicMethod, throwing 'The return Type contains some invalid type (i.e. null, ByRef)'. Which makes sense, since I understand that under the hood WidgetMeasurer returns an Int32&.

The question is, is there some first- or third-party technique I can employ to emit code mimicking the first two examples (which I empirically know work correctly)? If not, is this restriction a logical one?

EDIT: I've tried the equivalent System.Reflection.Emit code and got the same exception (as expected):

WidgetMeasurer GetMeasurerD()
{
    FieldInfo lengthField = typeof(Widget).GetField(nameof(Widget.Length));

    Type returnType = typeof(int).MakeByRefType();
    Type[] paramTypes = { typeof(Widget) };
    DynamicMethod method = new DynamicMethod("", returnType, paramTypes);

    ILGenerator il = method.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldflda, lengthField);
    il.Emit(OpCodes.Ret);

    return (WidgetMeasurer)method.CreateDelegate(typeof(WidgetMeasurer));
}
1 Answers
Related