c# - 我的简单 MSIL 有什么问题?

标签 c# cil reflection.emit

我正在尝试生成以下类:

public class MyType
{
    public string MyMethod() { return "Hi"; }
}

我的Emit代码如下:

var assemblyBuilder = GetAssemblyBuilder("MyAssembly");
var moduleBuilder = assemblyBuilder.DefineDynamicModule("MyModule");
var typeBuilder = moduleBuilder.DefineType("MyType", TypeAttributes.Public);
var methodBuilder = typeBuilder.DefineMethod("MyMethod", MethodAttributes.Public, typeof(string), new Type[] { });
var ilBuilder = methodBuilder.GetILGenerator();
ilBuilder.Emit(OpCodes.Nop);
ilBuilder.Emit(OpCodes.Ldstr, "Hi");
ilBuilder.Emit(OpCodes.Stloc_0);
ilBuilder.Emit(OpCodes.Br_S);
ilBuilder.Emit(OpCodes.Ldloc_0);
ilBuilder.Emit(OpCodes.Ret);
var type = typeBuilder.CreateType();

但是当我在 MyType 的实例上调用 MyMethod 时,我得到了一个 InvalidProgramException:Common Language Runtime detected an invalid program。

我已经尝试将返回类型更改为 void 并仅使用 EmitWriteLineEmit(OpCodes.Ret),它运行良好,所以它一定是我在这里写的 IL。

我在这里遗漏了什么明显的东西吗?清楚的解释会很有帮助,因为我刚刚开始使用 Emit。

来自评论的附加信息:

“原始”IL 取自 LINQ-pad 中的 IL 生成。

最佳答案

除了删除 @Kendall 指出的 OpCodes.Br_S 之外,您需要声明要将 "Hi" 存储到的局部变量:

ilBuilder.DeclareLocal(typeof(string));
ilBuilder.Emit(OpCodes.Nop);
ilBuilder.Emit(OpCodes.Ldstr, "Hi");
ilBuilder.Emit(OpCodes.Stloc_0);
ilBuilder.Emit(OpCodes.Ldloc_0);
ilBuilder.Emit(OpCodes.Ret);

此外,我认为整个事情可以缩短为(如果您上使用编译器优化构建您的类,您将得到):

ilBuilder.Emit(OpCodes.Ldstr, "Hi");
ilBuilder.Emit(OpCodes.Ret);

(只需加载字符串,将其放在计算堆栈的顶部,然后返回字符串)。

如果您想复制编译器优化关闭的版本,我认为这是您最初尝试做的:

Label returnLabel = ilBuilder.DefineLabel();

ilBuilder.DeclareLocal(typeof(string));
ilBuilder.Emit(OpCodes.Nop);
/* Load the string "HI" and put it on the evaluation stack. */
ilBuilder.Emit(OpCodes.Ldstr, "Hi");

/* Store "Hi" in the local variable we declared. */
ilBuilder.Emit(OpCodes.Stloc_0);

/* Jump to the return label, which is, err the next line anyway: */
ilBuilder.Emit(OpCodes.Br_S, returnLabel);

/* Mark "returnLabel" here so we can jump to it: */
ilBuilder.MarkLabel(returnLabel);    

/* Load the contents of our local variable, put it on the evaluation stack: */
ilBuilder.Emit(OpCodes.Ldloc_0);

/* Return "Hi", which is now back on top of the evaluation stack: */
ilBuilder.Emit(OpCodes.Ret);

你需要定义一个标签来分支(使用ILGenerator.DefineLabel,使用MarkLabel,然后将该标签传递给Emit你发出 OpCodes.Br_S

不过如您所见,对于这么短的方法,分支有点毫无意义。

关于c# - 我的简单 MSIL 有什么问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25551866/

相关文章:

.net - 为什么 ILGenerator.Emit() 在动态汇编中插入 nop 操作码?

c# - 将 lambda 作为 IL 流传递给辅助 AppDomain,然后使用 DynamicMethod 将其组装回去

c# - 使用 Reflection.Emit 创建一个实现接口(interface)的类

c# - 如何从 Azure 角色内部检测当前订阅 ID?

C# 对 datagridview 行中的相同值进行着色

c# - WPF ComboBox 自定义绑定(bind)

c# - Silverlight 3.0 C# - 使用 Methodbuilder 创建 SET 方法,并使用 ILGenerator 和 Emit 添加 MSIL

c# - 使用 Reflection.Emit 实例化具有泛型参数的泛型类型

c# - Reflection Emit 创建类实例

c# - 命令行 GPG 使用 c# 解密 - 密码?