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));
}
DynamicMethod
does not support ref returns, judging by this issue raised – LibyanWidgetMeasurer
without reflection that works as intended. For example,WidgetMeasurer m = w => ref w.Length; ref int x = m(new Widget());
won't compile because m returnsint
notref int
. – QuinteGetMeasurerA()(widget) = 7;
which does work – Libyanref
on the rhs in that assignment. – QuinteTypeBuilder
and got the same exception. – Prelacy