C# 发出类似IL的C方法IL,但获取System.InvalidProgrameException:公共语言运行库检测到无效程序
发出类似IL的C方法IL,但获取System.InvalidProgrameException:公共语言运行库检测到无效程序 例如:C# 发出类似IL的C方法IL,但获取System.InvalidProgrameException:公共语言运行库检测到无效程序,c#,clr,emit,C#,Clr,Emit,发出类似IL的C方法IL,但获取System.InvalidProgrameException:公共语言运行库检测到无效程序 例如: public static int BoolToInt(this bool input) { return input ? 1 : 0; } IL代码为: ExtensionDataGetter.BoolToInt: IL_0000: nop IL_0001: ldarg.0 IL_0002
public static int BoolToInt(this bool input)
{
return input ? 1 : 0;
}
IL代码为:
ExtensionDataGetter.BoolToInt:
IL_0000: nop
IL_0001: ldarg.0
IL_0002: brtrue.s IL_0007
IL_0004: ldc.i4.0
IL_0005: br.s IL_0008
IL_0007: ldc.i4.1
IL_0008: stloc.0
IL_0009: br.s IL_000B
IL_000B: ldloc.0
IL_000C: ret
我尝试使用Emit IL创建此方法:
class Program
{
static void Main(string[] args)
{
var result = CreateFunc()(true);
Console.WriteLine(result);
}
static Func<bool, int> CreateFunc()
{
var dm = new DynamicMethod("Test" + Guid.NewGuid().ToString(), typeof(int), new[] { typeof(bool) });
var il = dm.GetILGenerator();
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ldarg_0);
var labelTrue = il.DefineLabel();
var labelStloc = il.DefineLabel();
var labelReturn = il.DefineLabel();
il.Emit(OpCodes.Brtrue_S, labelTrue);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Br_S, labelStloc);
il.MarkLabel(labelTrue);
il.Emit(OpCodes.Ldc_I4_1);
il.MarkLabel(labelStloc);
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Br_S, labelReturn);
il.MarkLabel(labelReturn);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ret);
var funcType = System.Linq.Expressions.Expression.GetFuncType(typeof(bool), typeof(int));
return (Func<bool, int>)dm.CreateDelegate(funcType);
}
}
但要避免错误
System.InvalidProgramException
HResult=0x8013153A
Message=Common Language Runtime detected an invalid program.
Source=<Cannot evaluate the exception source>
StackTrace:
<Cannot evaluate the exception stack trace>
我试着根据我的逻辑写一个新版本,这是成功的。
但这不是eqauls演示方法的IL
using System;
using System.Reflection;
using System.Reflection.Emit;
class Program
{
static void Main(string[] args)
{
var func = CreateFunc();
Console.WriteLine(func(true));
Console.WriteLine(func(false));
}
static Func<bool, int> CreateFunc()
{
var dm = new DynamicMethod("Test" + Guid.NewGuid().ToString(), typeof(int), new[] { typeof(bool) });
var il = dm.GetILGenerator();
var labelTrue = il.DefineLabel();
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Brtrue_S, labelTrue);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ret);
il.MarkLabel(labelTrue);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ret);
var funcType = System.Linq.Expressions.Expression.GetFuncType(typeof(bool), typeof(int));
return (Func<bool, int>)dm.CreateDelegate(funcType);
}
}
由于使用stloc.0将值存储在局部变量中,因此需要声明它:
var il = dm.GetILGenerator();
il.DeclareLocal(typeof(int));
您的第二个版本没有使用局部变量,因此没有此问题
第一个版本是编译器在调试模式下发出的,但在发布模式下,它更像您的第二个示例,除了不需要的nop之外。因为您使用stloc.0将值存储在局部变量中,所以需要声明它:
var il = dm.GetILGenerator();
il.DeclareLocal(typeof(int));
您的第二个版本没有使用局部变量,因此没有此问题
第一个版本是编译器在调试模式下发出的,但在发布模式下,它更像您的第二个示例,只是nop是不必要的。查看C编译器生成的IL是一个避免麻烦的好主意。但请务必查看发布版本,它会将您从这个bug中解救出来。@HansPassant谢谢!这对我来说是一个很重要的概念。看看C编译器生成的IL是一个避免麻烦的好主意。但请务必查看发布版本,它会将您从这个bug中解救出来。@HansPassant谢谢!这对我来说是个重要的概念。