📜 ⬆️ ⬇️

Reflection.Emit: array initialization

The logical addition to the previous article would be a clear example, if only to show that the devil is not so bad as it is painted, and in fact, even if you need to build an array initializer through Reflection.Emit, then most of the extra gestures will take On itself API, and from you remains, mostly, only to lick the code invented by the compiler from the last article. In this example, I will limit myself to a simple static array on 3 System.Int32 elements.

Well, let's start with what almost every post about Reflection.Emit begins with - creating a dynamic assembly, module and type:

TypeBuilder l_typeBuilder = AppDomain.CurrentDomain. DefineDynamicAssembly ( new System.Reflection.AssemblyName("Reflection.Emit array initilization example"), System.Reflection.Emit.AssemblyBuilderAccess.RunAndSave ).//   DefineDynamicModule("Example").//  DefineType("ExampleClass");//  

That is ready TypeBuilder . One of the strange moments of the previous article was the nested type with the .size directive and the field corresponding to this type. You do not have to take care of this, because Microsoft has already thought about this: the TypeBuilder.DefineInitializedData method will come up with a class and a field, write the data where necessary, and come up with all the tinsel that can only be useful to them. By the way, this is the next step:

 FieldBuilder l_fieldBuilder = l_typeBuilder.DefineInitializedData("initialization_data", new byte[]{ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00 }, System.Reflection.FieldAttributes.Static); 

I did not bother with the name of the field and called it the way I called it. As it should be, the data of this array are three numbers (1,2,3) in little endian. Since the target array is static, then the attribute is appropriate (It is worth noting that this is still not our target array). The announcement of the target field will be, I think, already familiar to many:
')
 FieldBuilder l_fieldBuilder2 = l_typeBuilder.DefineField("m_array", typeof(int[]), System.Reflection.FieldAttributes.Static | System.Reflection.FieldAttributes.Public); 

A field as a field, nothing ordinary: static and public. But like any obedient (and maybe even naughty) static field, it must be initialized in a static constructor. Therefore, it's time to create the same static constructor. At this point, MS also has a squiggle:
 ConstructorBuilder l_cb = l_typeBuilder.DefineTypeInitializer(); 

After that, it remains only to create an ILGenerator and write the method body. The code is similar to the code from the previous article, except for the fact that opcodes are used for static fields:

 ILGenerator l_propGetILGen = l_cb.GetILGenerator(); l_propGetILGen.Emit(OpCodes.Ldc_I4, 3);//     l_propGetILGen.Emit(OpCodes.Newarr, typeof(int));//  ,   3  l_propGetILGen.Emit(OpCodes.Dup);// . InitializeArray  void,      ,        l_propGetILGen.Emit(OpCodes.Ldtoken, l_fieldBuilder);//     .     RVA    l_propGetILGen.EmitCall(OpCodes.Call, new System.Action<Array, RuntimeFieldHandle>(System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray).Method, new Type[] { });//     (   ) l_propGetILGen.Emit(OpCodes.Stsfld, l_fieldBuilder2); //    ()      l_propGetILGen.Emit(OpCodes.Ret); 

That's all. The answer to the question “What are two arrays for?” Is most likely to be the same — to ensure thread safety, the value of the target array must be changed by an atomic operation.
Full code:

 using System; using System.Collections.Generic; using System.Text; using System.Reflection.Emit; namespace ReflectionEmitArrayInitializerExample { class Program { static void Main(string[] args) { TypeBuilder l_typeBuilder = AppDomain.CurrentDomain. DefineDynamicAssembly ( new System.Reflection.AssemblyName("Reflection.Emit array initilization example"), System.Reflection.Emit.AssemblyBuilderAccess.RunAndSave ). DefineDynamicModule("Example"). DefineType("ExampleClass"); FieldBuilder l_fieldBuilder = l_typeBuilder.DefineInitializedData("initialization_data", new byte[]{ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00 }, System.Reflection.FieldAttributes.Static); FieldBuilder l_fieldBuilder2 = l_typeBuilder.DefineField("m_array", typeof(int[]), System.Reflection.FieldAttributes.Static | System.Reflection.FieldAttributes.Public); ConstructorBuilder l_cb = l_typeBuilder.DefineTypeInitializer(); ILGenerator l_propGetILGen = l_cb.GetILGenerator(); l_propGetILGen.Emit(OpCodes.Ldc_I4, 3); l_propGetILGen.Emit(OpCodes.Newarr, typeof(int)); l_propGetILGen.Emit(OpCodes.Dup); l_propGetILGen.Emit(OpCodes.Ldtoken, l_fieldBuilder); l_propGetILGen.EmitCall(OpCodes.Call, new System.Action<Array, RuntimeFieldHandle>(System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray).Method, new Type[] { }); l_propGetILGen.Emit(OpCodes.Stsfld, l_fieldBuilder2); l_propGetILGen.Emit(OpCodes.Ret); System.Type l_t = null; System.Reflection.FieldInfo l_pi = (l_t = l_typeBuilder.CreateType()).GetField("m_array"); int[] l_array = (int[])l_pi.GetValue(null); } } } 


l_array will become an array with three {1,2,3} elements.

Source: https://habr.com/ru/post/247201/


All Articles