2014-01-03 7 views
3

В основном я пытаюсь десериализовать данные, находящиеся внутри массива байтов, в объекты. Я пытаюсь использовать метод GetString для кодирования UTF8 для чтения строки. Вот часть моего кода:Common Language Runtime обнаружил недопустимую программу - ILGenerator

var mm = new DynamicMethod("get_value", typeof(object) 
         , new Type[] { typeof(byte[]), typeof(int), typeof(int), typeof(int) }); 

     var utf8 = Encoding.GetEncoding("utf-8"); //l.GetValue(null, null).GetType().GetMethod("GetString"); 

     var getstring = utf8.GetType().GetMethod("GetString", new Type[] { typeof(byte[]), typeof(int), typeof(int) }); 
     // var getString = Encoding.UTF8.GetType().GetMethod("GetString", new Type[] { typeof(byte[]), typeof(int), typeof(int) }); 

     var h = new EmitHelper(mm.GetILGenerator()); 

     var defaultCase = h.ILGenerator.DefineLabel(); 

     var lbs = new Label[] { h.DefineLabel(),h.DefineLabel()}; 

     var getInt32Method = typeof(BitConverter).GetMethod("ToInt32", new Type[] { typeof(byte[]), typeof(int) }); 

     //Arg0 = Byte [] , Arg1 = type, Arg2 = size, Arg3 = offset 
     h 
      .ldarg_1 
      [email protected](lbs) 
      .MarkLabel(defaultCase) 
      .ldnull 
      .ret(); 

     h 
      .MarkLabel(lbs[0]) 
      .ldarg_0 
      .ldarg_3 
      .call(getInt32Method) 
      .box(typeof(int)) 
      .ret(); 

     //THis is the function that is causing problem; If i remove this function works; 
     h 
      .MarkLabel(lbs[1]) 
      .ldarg_0 //Load array 
      .ldarg_3 //Load Offset (index) 
      .ldarg_2 //Load Size (count) 
      .callvirt(getstring) 
      .boxIfValueType(typeof(string)) 
      .ret(); 

     return (GetValueDelegate)mm.CreateDelegate(typeof(GetValueDelegate)); 

Я проверил метод подписи «GetString» за пределами этого кода, и она работает. Я попытался удалить «.boxIfAny», и я также попытался использовать «call», а не «callvirt». Насколько я понимаю, «callvirt» - это, например, методы, которые применяются в этом случае. Есть идеи?

+2

Используйте PEVerify, чтобы узнать, что не так. – leppie

+0

Не знал, что такое было такое. Googling сейчас ...;) – Faisal

ответ

3

Для вызова метода GetString требуется экземпляр.

я упростил свой код и сделал его в SSCCE:

using System; 
using System.Reflection.Emit; 
using System.Text; 

class GetStringDemo { 
    public static DynamicMethod GetStringForEncoding(Encoding encoding) { 

     var getstringMethod = encoding.GetType().GetMethod("GetString", 
      new Type[] { typeof(byte[]) });  
     var getStringCreator = new DynamicMethod("foo", typeof(string), 
      new Type[] { typeof(byte[]), encoding.GetType() }, typeof(void)); 
     ILGenerator gen = getStringCreator.GetILGenerator(); 

     gen.Emit(OpCodes.Ldarg_1); // this is the instance for callvirt 
     gen.Emit(OpCodes.Ldarg_0);   
     gen.Emit(OpCodes.Callvirt, getstringMethod); 
     gen.Emit(OpCodes.Box, typeof(string)); 
     gen.Emit(OpCodes.Ret); 

     return getStringCreator; 
    } 

    public static void Main() { 

     var utf8 = Encoding.GetEncoding("utf-8"); 
     var method = GetStringForEncoding(utf8); 
     Console.WriteLine(method.Invoke(null, new object[2] { 
      new byte[] { 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 
         0x32, 0x30, 0x31, 0x34, 0x21 }, 
      utf8 })); 
    } 
} 
// Output: 
Hello 2014! 

нагрузки фактической цели вызова перед вызовом h.ldarg_0 //Load array. В его отсутствие вы действительно получите System.InvalidProgramException, брошенный mscorlib.

+0

Это объясняет многое. Я отчасти новичок в ILGenerator и начал работать с ним, потому что данные, с которыми я работаю, получают огромные и простые процедуры отражения, которые не сокращают его из-за их скорости (или озера). Поэтому я экспериментирую с новым способом поддержания состояния своих бизнес-объектов. Этот код является частью хранилища Key-Value, которое я нахожу в процессе создания. Большое спасибо, и я обещаю вернуться с большим количеством проблем. – Faisal