我正在学习ref返回的细节,并且在发出一个通过引用返回的动态方法时遇到了困难。
手工制作的lambda表达式和现有方法按预期工作:
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;
}
但是发出动态方法失败了。 注意:我在这里使用Sigil。 抱歉,我对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();
}
这在
NewDynamicMethod
时失败,抛出 '返回类型包含一些无效类型(即null、ByRef)'
的异常。这很有道理,因为我了解到,在WidgetMeasurer
底层返回的是Int32&
。问题是,有没有我可以使用的第一方或第三方技术来发射代码,模仿前两个示例(我已经知道它们能够正确工作)?如果没有,这个限制是否是逻辑上的? 编辑:我已经尝试了等价的
System.Reflection.Emit
代码,并得到了相同的异常(如预期所述)。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
不支持引用返回,根据 这个 提出的问题。 - RobWidgetMeasurer
委托实例。例如,WidgetMeasurer m = w => ref w.Length; ref int x = m(new Widget());
不会编译,因为m返回的是int
而不是ref int
。 - Mike ZborayGetMeasurerA()(widget) = 7;
,这确实有效。 - RobTypeBuilder
生成一个返回引用实例方法,但是得到了相同的异常。 - user6027203