InvalidProgramException: (wrapper dynamic-method) object:GetField () 中的无效 IL 代码: IL_0000: ret

InvalidProgramException: Invalid IL code in (wrapper dynamic-method) object:GetField (): IL_0000: ret

如标​​题所述。但是,我正在尝试这样做:

  delegate char[] FieldDelegate();
   
  private FieldDelegate Get_InternalBuffer(StringBuilder sb)
  {
     var sbType = sb.GetType();
     var fieldInfo = sbType.GetField("m_ChunkChars", 
        BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
     
     var dynMethod = new DynamicMethod("GetField", typeof(char[]), new Type[0], true);
     ILGenerator ig = dynMethod.GetILGenerator();
     ig.Emit(OpCodes.ldflda, fieldInfo);
     ig.Emit(OpCodes.Ret);
     return dynMethod.CreateDelegate(typeof(FieldDelegate)) as FieldDelegate;
  }

短,我不知道为什么。我已经检查了 class 的 IL 代码,它只包含一个“char[] 缓冲区”来模拟我在这里所做的事情,它实际上正确地说明了这一点:“IL_0006: ret”作为一个 IL_instruction,那我做错了什么?

任何帮助都会很棒!

此致

我不是 100% 确定您要实现的实际目标是什么,但它是否必须是动态的/使用 Emit API?

如果不是,这里有一个有效的反射方法:

private static Func<char[]> Get_InternalBuffer_Reflection_Only(StringBuilder stringBuilder)
{
   Type sbType = stringBuilder.GetType();
   FieldInfo fieldInfo = sbType.GetField("m_ChunkChars",
   BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);

   Func<char[]> func = () => (char[])fieldInfo.GetValue(stringBuilder);
   return func;
}

有很多注意事项需要注意:

  • 您正在捕获 Delegate/Func 内的 StringBuilder,从而将其生命周期与返回的 Delegate/Func.
  • 联系起来
  • 每次要使用新的 StringBuilder
  • 时,您都必须支付 emitting/reflection 的开销

编辑:

为了提高性能,我认为您可以使用 Expression 或 Emit 来实现。使用 IL,我不确定您如何在动态创建的方法中捕获 StringBuilder 参数,但您可以稍微改变您的委托以获得相同的结果。

再次查看您的代码,它不起作用的原因是因为您在调用 Ldfld 时方法中的堆栈上实际上没有任何内容。 FieldInfo 单独简单地描述了如何获取值,您仍然需要对对象的引用以从中检索值。

更改您的委托,您可以这样做:

delegate char[] FieldDelegate(StringBuilder sb);

private static FieldDelegate Get_InternalBuffer()
{
    Type sbType = typeof(StringBuilder);
    FieldInfo fieldInfo = sbType.GetField("m_ChunkChars",
        BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);

    var dynMethod = new DynamicMethod("DynamicGetChunkChars", 
        typeof(char[]), new Type[] { sbType }, true);
    ILGenerator ig = dynMethod.GetILGenerator();
    ig.Emit(OpCodes.Ldarg_0);
    ig.Emit(OpCodes.Ldfld, fieldInfo);
    ig.Emit(OpCodes.Ret);
    return dynMethod.CreateDelegate(typeof(FieldDelegate)) as FieldDelegate;
}

static void Main(string[] args)
{
    var sb = new StringBuilder("test123");
    FieldDelegate getBuffer = Get_InternalBuffer();

    char[] ret = getBuffer(sb);

    Console.ReadLine();
}

您必须使用 StringBuilder 调用返回的方法。 这也意味着您现在可以缓存返回的方法并重新使用它。