简体   繁体   English

动态类型的Msil Emit静态数组

[英]Msil Emit static array in dynamic type

I'm trying to create a new type using Reflection.Emit (in c#). 我正在尝试使用Reflection.Emit(在c#中)创建一个新类型。

The code I want to create is something similar to 我想要创建的代码类似于

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

I first tried to define a field, and then set its value: 我首先尝试定义一个字段,然后设置其值:

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

but it doesn't work, since setValue is only supported for simple types (int, float, ...). 但它不起作用,因为setValue仅支持简单类型(int,float,...)。

Now I'm trying to use DefineInitializedData (much longer code which doesn't work...), but it does not generate any valid IL code. 现在我正在尝试使用DefineInitializedData(更长的代码,它不起作用......),但它不会生成任何有效的IL代码。

setValue is only supported for simple types (int, float, ...) setValue仅支持简单类型(int,float,...)

No, it's not. 不,这不对。 FieldBuilder inherits SetValue() from FieldInfo , but it doesn't make sense for FieldBuilder . FieldBuilderFieldInfo继承SetValue() ,但它对FieldBuilder没有意义。

There is FieldBuilder.SetConstant() , but it only works for const fields. FieldBuilder.SetConstant() ,但它只适用于const字段。 And you can't have const fields of reference types with values other than null . 并且您不能使用除null之外的值的引用类型的const字段。

What you need to do is the same thing any compiler would have to do: create a static constructor, create the array there and then assign it to the field: 你需要做的是任何编译器必须做的事情:创建一个静态构造函数,在那里创建数组然后将它分配给字段:

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);

If you look at the decompiled code generated by the C# compiler, you might see different IL, using something like <PrivateImplementationDetails>.__StaticArrayInitTypeSize=12 and RuntimeHelpers.InitializeArray() . 如果查看C#编译器生成的反编译代码,您可能会看到不同的IL,使用类似<PrivateImplementationDetails>.__StaticArrayInitTypeSize=12RuntimeHelpers.InitializeArray() That's an optimization and I think that if you're writing IL by hand, it's going to be simpler to use the normal method I showed above. 这是一个优化,我认为如果你手工编写IL,那么使用我上面展示的常规方法会更简单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM