C# IL代码操作可能会破坏运行时的稳定性

C# IL代码操作可能会破坏运行时的稳定性,c#,.net-4.0,il,C#,.net 4.0,Il,我当前有以下代码,当我运行它时,我得到错误代码操作可能会破坏运行时的稳定性(这是我更新的il代码,与信号匹配,但仍然无法工作) public static Func TestMethod() { var方法=新的DynamicMethod(“),typeof(Object),new[] { 类型(IDataReader) }); var il=method.GetILGenerator(); 标签whileIf=il.DefineLabel(); Label whileStart=il.Defi

我当前有以下代码,当我运行它时,我得到错误代码操作可能会破坏运行时的稳定性(这是我更新的il代码,与信号匹配,但仍然无法工作)

public static Func TestMethod()
{
var方法=新的DynamicMethod(“),typeof(Object),new[]
{
类型(IDataReader)
});
var il=method.GetILGenerator();
标签whileIf=il.DefineLabel();
Label whileStart=il.DefineLabel();
Label methodEnd=il.DefineLabel();
Emit(opcode.Newobj,typeof(List.GetConstructor)(新类型[0]);
发射(操作码Stloc_0);
发射(操作码Br_S,whileIf);
il.标记标签(whileStart);
发射(操作码Ldloc_0);
il.Emit(操作码.Ldarg_0);
发射(操作码Ldc_I4_0);
Emit(opcode.Callvirt,typeof(IDataRecord.GetMethod)(“GetString”);
Emit(opcode.Callvirt,typeof(List.GetMethod)(“Add”);
il.标记标签(whileIf);
il.Emit(操作码.Ldarg_0);
Emit(opcode.Callvirt,typeof(IDataReader.GetMethod(“Read”));
il.Emit(操作码.Brtrue_S,whileStart);
发射(操作码Ldloc_0);
发射(操作码Ret);
return(Func)方法.CreateDelegate(typeof(Func));
}
它是根据以下代码创建的:

public List<string> method(IDataReader dataReader)
    {
        var result = new List<string>();
        while (dataReader.Read())
            result.Add(dataReader.GetString(0));
        return result;
    }
公共列表方法(IDataReader数据读取器)
{
var result=新列表();
while(dataReader.Read())
Add(dataReader.GetString(0));
返回结果;
}
哪个基因编码以下IL代码:

IL_0000:  nop         
IL_0001:  newobj      System.Collections.Generic.List<System.String>..ctor
IL_0006:  stloc.0     // result
IL_0007:  br.s        IL_0017
IL_0009:  ldloc.0     // result
IL_000A:  ldarg.1     
IL_000B:  ldc.i4.0    
IL_000C:  callvirt    System.Data.IDataRecord.GetString
IL_0011:  callvirt    System.Collections.Generic.List<System.String>.Add
IL_0016:  nop         
IL_0017:  ldarg.1     
IL_0018:  callvirt    System.Data.IDataReader.Read
IL_001D:  stloc.2     // CS$4$0001
IL_001E:  ldloc.2     // CS$4$0001
IL_001F:  brtrue.s    IL_0009
IL_0021:  ldloc.0     // result
IL_0022:  stloc.1     // CS$1$0000
IL_0023:  br.s        IL_0025
IL_0025:  ldloc.1     // CS$1$0000
IL_0026:  ret  
IL_0000:nop
IL_0001:newobj系统.Collections.Generic.List..ctor
IL_0006:stloc.0//结果
IL_0007:br.s IL_0017
IL_0009:ldloc.0//结果
IL_000A:ldarg.1
IL_000B:ldc.i4.0
IL_000C:callvirt System.Data.IDataRecord.GetString
IL_0011:callvirt System.Collections.Generic.List.Add
IL_0016:没有
IL_0017:ldarg.1
IL_0018:callvirt System.Data.IDataReader.Read
IL_001D:stloc.2//CS$4$0001
ILU 001E:ldloc.2//CS$4$0001
IL_001F:brtrue.s IL_0009
IL_0021:ldloc.0//结果
IL_0022:stloc.1//CS$1$0000
ILU 0023:br.s ILU 0025
IL_0025:ldloc.1//CS$1$0000
IL_0026:ret
我在IL中编写这段代码,因为我最终将扩展代码,并动态创建这段代码以从TArg填充类型。很抱歉,我没有visual studio提供给我的更多信息

这是我的sigil代码,可以正常工作和运行:

var emiter = Emit<Func<IDataReader, List<String>>>.NewDynamicMethod("MyMethod");

            var whileIf = emiter.DefineLabel("whileIf");
            var whileStart = emiter.DefineLabel("whileStart");

            emiter.DeclareLocal(typeof(List<string>), "0");

            emiter.NewObject<List<String>>();
            emiter.StoreLocal("0");
            emiter.Branch(whileIf);
            emiter.MarkLabel(whileStart);
            emiter.LoadLocal("0");
            emiter.LoadArgument(0);
            emiter.LoadConstant(0);
            emiter.CallVirtual(typeof(IDataRecord).GetMethod("GetString"));
            emiter.CallVirtual(typeof(List<string>).GetMethod("Add"));
            emiter.MarkLabel(whileIf);
            emiter.LoadArgument(0);
            emiter.CallVirtual(typeof(IDataReader).GetMethod("Read"));
            emiter.BranchIfTrue(whileStart);
            emiter.LoadLocal("0");
            emiter.Return();
            Func<IDataReader, List<string>> result = emiter.CreateDelegate();

            Disassembler<Func<IDataReader, List<string>>>.Disassemble( result );

            return result;
var emitter=Emit.NewDynamicMethod(“MyMethod”);
var whileIf=排放者定义标签(“whileIf”);
var whileStart=emitter.DefineLabel(“whileStart”);
排放者申报(列表类型,“0”);
emitter.NewObject();
emitter.StoreLocal(“0”);
发射极分支(whileIf);
发射器。标记标签(whileStart);
emitter.LoadLocal(“0”);
emitter.LoadArgument(0);
emitter.LoadConstant(0);
CallVirtual(typeof(IDataRecord).GetMethod(“GetString”);
CallVirtual(typeof(List).GetMethod(“Add”);
发射器。标记标签(whileIf);
emitter.LoadArgument(0);
CallVirtual(typeof(IDataReader).GetMethod(“Read”);
布朗希夫特街(惠勒斯特);
emitter.LoadLocal(“0”);
emitter.Return();
Func result=emitter.CreateDelegate();
拆卸器。拆卸(结果);
返回结果;

这通常意味着堆栈不平衡或调用类型错误(静态与虚拟)。我不在电脑前检查堆栈状态,但是:如果您不确定,我强烈建议您使用“sigil”之类的工具。它被明确设计为在您在emit中出错时立即告诉您,而不是在您以后运行它时告诉您。一旦你成功了,它就会准确地告诉你问题所在

但是,这些方法肯定是错误的:

    il.Emit( OpCodes.Ldarg_0 );
    il.MarkLabel( whileIf );

第一次通过它直接分支到whileIf,它让您在空堆栈上执行调用。

当我编写更多IL时,我编写了这些helper方法,让我创建委托,同时生成调试程序集。拥有该组件对于运行反射器工具和验证非常有用。


这是我的实现,我基本上从未在我的不同项目之间更改它

您是否熟悉
AssemblyBuilder
?如果使用它来创建方法,则可以将程序集保存到磁盘,并对生成的程序集运行PEVerify。这通常会告诉你出了什么问题。不,但谢谢,我会研究一下。你有一小段代码作为例子吗?现在没有,但如果我可以,如果你还没有一个好的解决方案,我会检查并发布一些东西。专业提示:编译检查IL时,在发布模式下构建-不调试第二个专业提示:除非你这样做是为了好玩,考虑使用像DAPPER这样的工具来处理所有这些东西,什么是“代码”>“调用Virt”?< Gabe >“静态调用”和“虚拟CALI”已经查看了SIGIL,并在其中写入了IL,并且它完全地运行了任何问题,可能是什么问题。谢谢。“卫国明,你修复了我说的断枝了吗?”杰克“Calvit”堆栈上至少需要一项-目标对象引用。它还需要所有参数(没有用于读取的参数)-在调用callvirt之前需要加载一个值,而原始IL则不需要。我无法在没有看到它的情况下对sigil代码进行评论,但我的猜测是:您颠倒了我引用的两行代码
    il.Emit( OpCodes.Ldarg_0 );
    il.MarkLabel( whileIf );