Msil以动态类型发射静态数组



我正在尝试使用Reflection.Emit(在c#中)创建一个新类型。

我想要创建的代码类似于

public class 
{
   public static int[] A = new int[] {1, 2, 3};
}

我首先尝试定义一个字段,然后设置它的值:

var fb = tb.DefineField("A", FieldAttributes.Public | FieldAttributes.Static);
fb.SetValue(null, new int[] {1, 2, 3});

但它不起作用,因为setValue只支持简单类型(int、float…)

现在我正在尝试使用DefineInitializedData(更长的代码,不起作用…),但它不会生成任何有效的IL代码。

setValue仅支持简单类型(int、float…)

不,不是。FieldBuilderFieldInfo继承了SetValue(),但对FieldBuilder来说没有意义。

FieldBuilder.SetConstant(),但它只适用于const字段。并且不能使引用类型的const字段的值不是null

您需要做的事情与任何编译器都必须做的事情相同:创建一个静态构造函数,在那里创建数组,然后将其分配给字段:

var fb = tb.DefineField("A", typeof(int[]), FieldAttributes.Public | FieldAttributes.Static);
var ctor = tb.DefineTypeInitializer();
var il = ctor.GetILGenerator();
// new int[3]
il.Emit(OpCodes.Ldc_I4_3);
il.Emit(OpCodes.Newarr, typeof(int));
// array[0] = 1
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Stelem_I4);
// array[1] = 2
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ldc_I4_2);
il.Emit(OpCodes.Stelem_I4);
// arr[2] = 3
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldc_I4_2);
il.Emit(OpCodes.Ldc_I4_3);
il.Emit(OpCodes.Stelem_I4);
// A = array
il.Emit(OpCodes.Stsfld, fb);
il.Emit(OpCodes.Ret);

如果您查看C#编译器生成的反编译代码,您可能会看到不同的IL,使用类似<PrivateImplementationDetails>.__StaticArrayInitTypeSize=12RuntimeHelpers.InitializeArray()的代码。这是一个优化,我认为如果你手工编写IL,使用我上面展示的普通方法会更简单。

相关内容

  • 没有找到相关文章

最新更新