【问题标题】:InvalidProgramException: Invalid IL code in (wrapper dynamic-method) object:GetField (): IL_0000: retInvalidProgramException:(包装器动态方法)对象中的无效 IL 代码:GetField():IL_0000:ret
【发布时间】:2020-11-03 00:51:47
【问题描述】:

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

  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;
  }

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

任何帮助都会很棒!

最好的问候

【问题讨论】:

  • 这就像你问了自己一个问题。我的意思是这里确实缺乏信息。这个问题需要更清楚
  • 您还需要什么?编辑了代表以显示我尝试创建哪个,对不起,我没有看到

标签: c# cil


【解决方案1】:

我不能 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 时,都必须支付发射/反射的开销

编辑:

为了提高性能,我认为您可以使用 Expression 或 Emit 来做到这一点。对于 IL,我不确定您如何在动态创建的方法中捕获 StringBuilder 参数,但您可以稍微更改您的 Delegate 以获得相同的结果。

再次查看您的代码,它不起作用的原因是因为您正在调用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 调用返回的方法。 这也意味着您现在可以缓存返回的方法并重用它。

【讨论】:

  • 是的,我希望 EmitApi 的性能能够避免反射代码,因为我将不得不在循环中使用这种方法!
  • 这里的纯反射代码会破坏性能 4ever。
  • 太好了,非常感谢!我只是无法正确理解为什么您需要将此 Stringbuilder 实例传递给动态方法以及为什么我的方法不起作用,因为我也说过。 “sbBuffer.GetType()”这实际上应该在我的脑海中至少可以作为您的解决方案?显然不是:D thx alot tho!
猜你喜欢
  • 1970-01-01
  • 2017-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多