Исключение InvalidProgramException: недопустимый код IL в (оболочке динамического метода) объект:getField (): IL_0000: ret

#c# #cil

#c# #cil

Вопрос:

как указано в названии. Тем не менее, я пытаюсь это сделать:

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

Короче говоря, я понятия не имею, почему. Я проверил IL-код класса, содержащего только «char[] buffer», чтобы имитировать то, что я здесь делаю, и на самом деле в нем правильно указано следующее: «IL_0006: ret» как одна IL_instruction, так что я делаю не так?

Любая помощь была бы потрясающей!

с наилучшими пожеланиями

Комментарии:

1. Это похоже на то, что вы задали вопрос самому себе. Я имею в виду, что здесь явно не хватает информации. Вопрос нуждается в большей ясности

2. что еще вам нужно? ОТРЕДАКТИРОВАЛ делегат, чтобы показать, какой из них я пытаюсь создать, sry, я этого не видел

Ответ №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;
}
  

Есть много предостережений, о которых нужно знать:

  • Вы фиксируете StringBuilder внутри делегата / функции и, таким образом, привязываете его время жизни к возвращаемому делегату / функции.
  • Вам придется оплачивать накладные расходы на излучение / отражение каждый раз, когда вы хотите использовать новый StringBuilder

Редактировать:

Для повышения производительности я думаю, вы можете либо сделать это с помощью 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 помощью .
Это также означает, что теперь вы можете кэшировать возвращенный метод и использовать его повторно.

Комментарии:

1. Да, я хочу, чтобы EmitApi для производительности избегал кода отражения, поскольку мне придется использовать этот метод в цикле!

2. Чистый код отражения здесь в 4 раза снизил бы производительность.

3. Замечательно, большое спасибо! я просто не мог правильно понять, почему вам нужно передать этот экземпляр Stringbuilder в динамический метод и почему мой подход не работает, поскольку я тоже говорю. «sbBuffer. GetType()» это должно быть на самом деле в моей голове, по крайней мере, работать как ваше решение? по-видимому, нет: D большое спасибо!