如何发出返回ref的动态方法?

时间:2017-07-26 00:57:13

标签: c# reflection delegates reflection.emit ref

我正在浏览ref返回的来龙去脉,并且无法发出通过ref返回的动态方法。

手工制作的lambdas和现有方法按预期工作:

TB_KELUHAN

但是发出动态方法失败了。 注意:我在这里使用Sigil。道歉,我对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; } 不熟悉。

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。这是有道理的,因为我知道引擎盖'The return Type contains some invalid type (i.e. null, ByRef)'会返回WidgetMeasurer

问题是,是否有一些第一方或第三方技术可以用来发出模仿前两个例子的代码(我凭经验知道它可以正常工作)?如果没有,这个限制是否合乎逻辑?

编辑:我已尝试过等效的Int32&代码并获得相同的异常(如预期的那样):

System.Reflection.Emit

1 个答案:

答案 0 :(得分:2)

我不知道为什么DynamicMethod存在这种限制,但以下内容对我有用。一个区别是我们手动定义自己的动态组件。另一个区别是,由于这是单独的程序集,Widget需要公开(或者如果你恰当地命名动态程序集,你可以在父程序集上使用InternalsVisibleTo。)

static void Main(string[] args)
{
    var widget = new Widget();
    GetLengthMeasurer()(widget) = 7;
    Console.WriteLine(widget.Length);
}

private static WidgetMeasurer GetLengthMeasurer()
{
    var fieldInfo = typeof(Widget).GetField("Length");
    var asmName = new AssemblyName("WidgetDynamicAssembly." + Guid.NewGuid().ToString());
    var asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndCollect);
    var moduleBuilder = asmBuilder.DefineDynamicModule("<Module>");
    var typeBuilder = moduleBuilder.DefineType("WidgetHelper");
    var methodBuilder = typeBuilder.DefineMethod("GetLength", MethodAttributes.Static | MethodAttributes.Public, typeof(int).MakeByRefType(), new[] { typeof(Widget) });
    var ilGen = methodBuilder.GetILGenerator();
    ilGen.Emit(OpCodes.Ldarg_0);
    ilGen.Emit(OpCodes.Ldflda, fieldInfo);
    ilGen.Emit(OpCodes.Ret);
    var type = typeBuilder.CreateType();
    var mi = type.GetMethod(methodBuilder.Name);
    var del = (WidgetMeasurer)mi.CreateDelegate(typeof(WidgetMeasurer));
    return del;
}

输出:

  

7