Msil发射动态类型的静态数组 [英] Msil Emit static array in dynamic type

查看:81
本文介绍了Msil发射动态类型的静态数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to create a new type using Reflection.Emit (in c#).

我要创建的代码类似于

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

但是它不起作用,因为setValue仅支持简单类型(int,float等).

but it doesn't work, since setValue is only supported for simple types (int, float, ...).

现在我正在尝试使用DefineInitializedData(更长的代码无法正常工作...),但是它不会生成任何有效的IL代码.

Now I'm trying to use DefineInitializedData (much longer code which doesn't work...), but it does not generate any valid IL code.

推荐答案

setValue仅适用于简单类型(int,float等)

setValue is only supported for simple types (int, float, ...)

不,不是. FieldBuilder 继承自 FieldInfo SetValue(),但对于 FieldBuilder 而言却没有意义.

No, it's not. FieldBuilder inherits SetValue() from FieldInfo, but it doesn't make sense for FieldBuilder.

FieldBuilder.SetConstant() ,但仅适用于 const 字段.而且,引用类型的 const 字段不能具有 null 以外的值.

There is FieldBuilder.SetConstant(), but it only works for const fields. And you can't have const fields of reference types with values other than null.

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

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

如果查看C#编译器生成的反编译代码,则可能会使用< PrivateImplementationDetails> .__ StaticArrayInitTypeSize = 12

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(). 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.

这篇关于Msil发射动态类型的静态数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆