我正在尝试使用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代码。

最佳答案

仅对简单类型(int,float等)支持setValue


不,这不对。 FieldBuilderSetValue()继承FieldInfo,但是对于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#编译器生成的反编译代码,则可能会使用<PrivateImplementationDetails>.__StaticArrayInitTypeSize=12RuntimeHelpers.InitializeArray()之类的内容看到不同的IL。这是一个优化,我认为,如果您是手工编写IL,那么使用上面显示的常规方法会更简单。

09-10 08:54
查看更多