Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create multi-dimensional array using Reflection.Emit

Tags:

c#

emit

I want to create a multi-dimensional array using Reflection.Emit and set it's element. Like the following C# code:

int[,] nums = new int[2, 2];
nums[1, 1] = 2;

And turn into IL code:

IL_0000: nop
IL_0001: ldc.i4.2
IL_0002: ldc.i4.2
IL_0003: newobj instance void int32[0..., 0...]::.ctor(int32, int32)
IL_0008: stloc.0
IL_0009: ldloc.0
IL_000a: ldc.i4.1
IL_000b: ldc.i4.1
IL_000c: ldc.i4.2
IL_000d: call instance void int32[0..., 0...]::Set(int32, int32, int32)

The IL code to create array:

newobj instance void int32[0..., 0...]::.ctor(int32, int32)

And the IL code to set the array's element:

call instance void int32[0..., 0...]::Set(int32, int32, int32)

What kind of IL Generator.Emit() code corresponding to those two IL sentence?

like image 266
nineveh.Y Avatar asked Mar 27 '16 18:03

nineveh.Y


2 Answers

You can almost translate that IL verbally:

il.Emit(OpCodes.Ldc_I4_2);
il.Emit(OpCodes.Ldc_I4_2);

var constructor = typeof(int[,]).GetConstructor(new Type[]{ typeof(int), typeof(int) });
il.Emit(OpCodes.Newobj, constructor);
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ldc_I4_2);

var setMethod = typeof(int[,]).GetMethod("Set");
il.Emit(OpCodes.Call, setMethod);

Of course, you need to use reflection to actually get the ConstructorInfo and the MethodInfo object you need for the Newobj and Call codes.

like image 71
poke Avatar answered Sep 20 '22 17:09

poke


Here is an example:

DynamicMethod method =
    new DynamicMethod("Test" , typeof(int[,]), new Type[]{});

var generator = method.GetILGenerator();

//get the constructor that takes in 2 integers (the dimensions of the array)
var constructor = typeof (int[,])
    .GetConstructor(new {typeof (int), typeof (int)});

//get the Set method that takes in 3 integers; 2 indexes and the value 
var set_method = typeof(int[,])
    .GetMethod("Set", new[] { typeof(int), typeof(int), typeof(int) });

var local = generator.DeclareLocal(typeof (int[,])); //local variable to reference the array

generator.Emit(OpCodes.Ldc_I4_2);
generator.Emit(OpCodes.Ldc_I4_2);
generator.Emit(OpCodes.Newobj, constructor); //invoke the constructor to create the array
generator.Emit(OpCodes.Stloc, local);
generator.Emit(OpCodes.Ldloc, local);
generator.Emit(OpCodes.Ldc_I4_1);
generator.Emit(OpCodes.Ldc_I4_1);
generator.Emit(OpCodes.Ldc_I4_2);
generator.Emit(OpCodes.Call, set_method); //call the Set method to set the value
generator.Emit(OpCodes.Ldloc, local);
generator.Emit(OpCodes.Ret);

var result_method = (Func<int[,]>)method.CreateDelegate(typeof (Func<int[,]>));

var result = result_method(); //returns the array

This example creates a dynamic method that creates the array, fills the value in [1,1], and then returns that array.

like image 24
Yacoub Massad Avatar answered Sep 20 '22 17:09

Yacoub Massad