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

Msil Emit static array in dynamic type

我正在尝试使用 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 is only supported for simple types (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,使用我上面展示的常规方法会更简单。