如何使用 Reflection.Emit 创建静态字段
How do I create a Static Field using Reflection.Emit
我正在尝试使用 Reflection.Emit 创建一个静态字段。
但是,当我尝试加载它时出现 InvalidProgramException。
以下代码重现了我的问题。
行:
generator.Emit(OpCodes.Ldsfld, builderField);
导致以下异常:
Unhandled Exception: System.InvalidProgramException: Common Language Runtime detected an invalid program.
没有这一行,程序运行正常,并且 returns "Test" 符合预期
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(
new AssemblyName(Guid.NewGuid().ToString()),
AssemblyBuilderAccess.Run);
var module = assemblyBuilder.DefineDynamicModule("module1");
var typeBuilder = module.DefineType("MyType", TypeAttributes.Public|TypeAttributes.Class);
typeBuilder.AddInterfaceImplementation(typeof(IMyType));
var builderField = typeBuilder.DefineField("_builder", typeof(StringBuilder), FieldAttributes.Static | FieldAttributes.Private);
var methodBuilder = typeBuilder.DefineMethod(
"UseStringBuilder",
MethodAttributes.Public | MethodAttributes.Virtual,
typeof(string),
new Type[0]);
var generator = methodBuilder.GetILGenerator();
//this line causes InvalidProgramException, without this line it works
generator.Emit(OpCodes.Ldsfld, builderField);
generator.Emit(OpCodes.Ldstr, "Test");
generator.Emit(OpCodes.Ret);
var typeInfo = typeBuilder.CreateTypeInfo();
var myType = typeInfo.AsType();
IMyType instance = (IMyType)Activator.CreateInstance(myType);
instance.UseStringBuilder();
我知道我没有将 StringBuilder 用于任何东西,只是将它放在堆栈上,并且它将是空的,因为它没有被初始化,但它是一个简化版本(为了重现问题)一个更大的程序,它延迟初始化字段,所以我需要将它加载到堆栈上,这样我就可以检查它是否为 null。但是,ldsfld 指令在我执行任何操作之前使程序崩溃。
此代码的工作版本的 ILSPY 如下所示:
// Fields
.field private static class [System.Runtime]System.Text.StringBuilder _builder
// Methods
.method public final hidebysig newslot virtual
instance string UseStringBuilder () cil managed
{
// Method begins at RVA 0x20ee
// Code size 28 (0x1c)
.maxstack 8
IL_0000: ldsfld class [System.Runtime]System.Text.StringBuilder JsonicsTests.MyType::_builder
IL_0005: brtrue.s IL_0011
IL_0007: newobj instance void [System.Runtime]System.Text.StringBuilder::.ctor()
IL_000c: stsfld class [System.Runtime]System.Text.StringBuilder JsonicsTests.MyType::_builder
IL_0011: ldsfld class [System.Runtime]System.Text.StringBuilder JsonicsTests.MyType::_builder
IL_0016: callvirt instance string [System.Runtime]System.Object::ToString()
IL_001b: ret
}
使用 Reflection.Emit 创建和使用静态字段的正确方法是什么?
如果相关的话,我 运行 在 linux 上使用 .net core 1.1。
你有一个不平衡堆栈的问题:你在函数结束后在堆栈上留下了一个值。尝试:
generator.Emit(OpCodes.Ldsfld, builderField);
generator.Emit(OpCodes.Pop); // Remove the value from the stack
我正在尝试使用 Reflection.Emit 创建一个静态字段。
但是,当我尝试加载它时出现 InvalidProgramException。
以下代码重现了我的问题。
行:
generator.Emit(OpCodes.Ldsfld, builderField);
导致以下异常:
Unhandled Exception: System.InvalidProgramException: Common Language Runtime detected an invalid program.
没有这一行,程序运行正常,并且 returns "Test" 符合预期
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(
new AssemblyName(Guid.NewGuid().ToString()),
AssemblyBuilderAccess.Run);
var module = assemblyBuilder.DefineDynamicModule("module1");
var typeBuilder = module.DefineType("MyType", TypeAttributes.Public|TypeAttributes.Class);
typeBuilder.AddInterfaceImplementation(typeof(IMyType));
var builderField = typeBuilder.DefineField("_builder", typeof(StringBuilder), FieldAttributes.Static | FieldAttributes.Private);
var methodBuilder = typeBuilder.DefineMethod(
"UseStringBuilder",
MethodAttributes.Public | MethodAttributes.Virtual,
typeof(string),
new Type[0]);
var generator = methodBuilder.GetILGenerator();
//this line causes InvalidProgramException, without this line it works
generator.Emit(OpCodes.Ldsfld, builderField);
generator.Emit(OpCodes.Ldstr, "Test");
generator.Emit(OpCodes.Ret);
var typeInfo = typeBuilder.CreateTypeInfo();
var myType = typeInfo.AsType();
IMyType instance = (IMyType)Activator.CreateInstance(myType);
instance.UseStringBuilder();
我知道我没有将 StringBuilder 用于任何东西,只是将它放在堆栈上,并且它将是空的,因为它没有被初始化,但它是一个简化版本(为了重现问题)一个更大的程序,它延迟初始化字段,所以我需要将它加载到堆栈上,这样我就可以检查它是否为 null。但是,ldsfld 指令在我执行任何操作之前使程序崩溃。
此代码的工作版本的 ILSPY 如下所示:
// Fields
.field private static class [System.Runtime]System.Text.StringBuilder _builder
// Methods
.method public final hidebysig newslot virtual
instance string UseStringBuilder () cil managed
{
// Method begins at RVA 0x20ee
// Code size 28 (0x1c)
.maxstack 8
IL_0000: ldsfld class [System.Runtime]System.Text.StringBuilder JsonicsTests.MyType::_builder
IL_0005: brtrue.s IL_0011
IL_0007: newobj instance void [System.Runtime]System.Text.StringBuilder::.ctor()
IL_000c: stsfld class [System.Runtime]System.Text.StringBuilder JsonicsTests.MyType::_builder
IL_0011: ldsfld class [System.Runtime]System.Text.StringBuilder JsonicsTests.MyType::_builder
IL_0016: callvirt instance string [System.Runtime]System.Object::ToString()
IL_001b: ret
}
使用 Reflection.Emit 创建和使用静态字段的正确方法是什么?
如果相关的话,我 运行 在 linux 上使用 .net core 1.1。
你有一个不平衡堆栈的问题:你在函数结束后在堆栈上留下了一个值。尝试:
generator.Emit(OpCodes.Ldsfld, builderField);
generator.Emit(OpCodes.Pop); // Remove the value from the stack