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

标签 c# reflection delegates reflection.emit ref

我正在浏览 ref 返回的来龙去脉,但在发出由 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 处失败,抛出 'The return Type contains some invalid type (i.e.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 存在此限制,但以下内容对我有用。一个区别是我们手动定义我们自己的动态程序集。另一个区别是,由于这是单独的程序集,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

关于c# - 如何发出返回 ref 的动态方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45315718/

相关文章:

c# - 获得最前沿的控制

c# - 由于抽象类,无法传递类来添加方法

java - 在 Java 中,如何将类型列表中的所有静态字段作为其类的对象(而不是 Field 实例)?

c# - 多线程更新主窗体

c# - 如何包装一个函数及其参数......有点像 "super delegate"?

ios - 快速从单独的 View Controller 调用函数

c# - Entity Framework 将小数位附加到 decimal(10,0) 类型的字段

c# - 仅将 BindingList 的某些属性绑定(bind)到 DataGrid

c# - AppDomain 通信和性能

c# 4.0 使用(指定的属性和 attribute.data)获取类属性