Как создать многомерный массив с помощью Reflection.Emit

Я хочу создать многомерный массив с помощью Reflection.Emit и установить его элемент. Например, следующий код C#:

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

И превратить в IL-код:

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)

Код IL для создания массива:

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

И код IL для установки элемента массива:

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

Какой код IL Generator.Emit() соответствует этим двум предложениям IL?


person nineveh.Y    schedule 27.03.2016    source источник


Ответы (2)


Вы можете почти перевести этот IL устно:

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

Конечно, вам нужно использовать отражение, чтобы фактически получить объекты ConstructorInfo и MethodInfo, необходимые для кодов Newobj и Call.

person poke    schedule 27.03.2016
comment
спасибо, сначала я написал [ , ] как [ ][ ] и получил неправильный код IL, теперь я вижу - person nineveh.Y; 27.03.2016
comment
[,] и [][] относятся к двум разным типам массивов, см. -of-arrays">этот вопрос для получения дополнительной информации о различиях. - person poke; 27.03.2016

Вот пример:

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

В этом примере создается динамический метод, который создает массив, заполняет значение в [1,1], а затем возвращает этот массив.

person Yacoub Massad    schedule 27.03.2016