公共语言运行时检测到一个无效程序 - ILGenerator

3

基本上,我正在尝试将位于字节数组中的数据反序列化为对象。我正在尝试使用UTF8编码的GetString方法来读取字符串。这是我的代码的一部分:

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
            .@switch(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
不知道有这样的东西。现在正在谷歌搜索... ;) - Faisal
1个回答

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 前,先加载实际的调用目标。如果没有加载,你将会得到由mscorlib抛出的System.InvalidProgramException异常。


这解释了很多问题。我对ILGenerator还比较新,开始使用它是因为我处理的数据变得越来越庞大,简单的反射例程由于速度(或缺乏速度)而无法胜任。因此,我正在尝试一种新的方法来维护我的业务对象的状态。这段代码是我正在构建的键值存储的一部分。非常感谢,我保证会带着更多问题回来。 - Faisal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接