2011-06-08 6 views
7

Estoy escribiendo algunas instituciones de IL para crear matrices int y double utilizando System.Reflection.Emit espacio de nombres.Generación de IL para matrices dobles

Para crear int array Estoy usando el siguiente código.

LocalBuilder arr = gen.DeclareLocal(typeof(int)); 
gen.Emit(OpCodes.Ldc_I4_1); 
gen.Emit(OpCodes.Newarr, typeof(int)); 
gen.Emit(OpCodes.Stloc, arr); 
gen.Emit(OpCodes.Ldloc, arr); 
gen.Emit(OpCodes.Ldc_I4_0); 
gen.Emit(OpCodes.Ldc_I4, 500); 
gen.Emit(OpCodes.Stelem_I4); 

gen.Emit(OpCodes.Ldloc, arr); 
gen.Emit(OpCodes.Ldc_I4_0); 
gen.Emit(OpCodes.Ldelem_I4); 
gen.Emit(OpCodes.Call,typeof(Console).GetMethod("WriteLine",new Type[]{typeof(int)})); 

Está funcionando como se esperaba e imprime 500 en la consola.

De la misma manera que traté de crear double matriz como se muestra a continuación.

LocalBuilder arr = gen.DeclareLocal(typeof(double)); 
gen.Emit(OpCodes.Ldc_I4_1); 
gen.Emit(OpCodes.Newarr, typeof(double)); 
gen.Emit(OpCodes.Stloc, arr); 
gen.Emit(OpCodes.Ldloc, arr); 
gen.Emit(OpCodes.Ldc_I4_0); 
gen.Emit(OpCodes.Ldc_R8, 500D); 
gen.Emit(OpCodes.Stelem_R8); 

gen.Emit(OpCodes.Ldloc, arr); 
gen.Emit(OpCodes.Ldc_I4_0); 
gen.Emit(OpCodes.Ldelem_I8); 
gen.Emit(OpCodes.Call,typeof(Console).GetMethod("WriteLine",new Type[]{typeof(double)})); 

Desafortunadamente esto no funciona y cuando inspeccione generó conjunto usando pereview me dio error de seguimiento.

Microsoft (R) .NET Framework PE Verifier. Version 4.0.30319.1 
Copyright (c) Microsoft Corporation. All rights reserved. 

[IL]: Error: [C:\temp\Research\Research\bin\Debug\MyMod.exe : Foo::Main][offset 0x00000006][found ref array md 
array 'System.Double[]'][expected Double] Unexpected type on the stack. 
[IL]: Error: [C:\temp\Research\Research\bin\Debug\MyMod.exe : Foo::Main][offset 0x00000012] Expected single di 
mension array. 
2 Error(s) Verifying MyMod.exe 

Además, inspeccioné generó conjunto usando ildasm

.method privatescope static void Main$PST06000001() cil managed 
{ 
    .entrypoint 
    // Code size  28 (0x1c) 
    .maxstack 3 
    .locals init (float64 V_0) 
    IL_0000: ldc.i4.1 
    IL_0001: newarr  [mscorlib]System.Double 
    IL_0006: stloc.0 
    IL_0007: ldloc.0 
    IL_0008: ldc.i4.0 
    IL_0009: ldc.r8  500. 
    IL_0012: stelem.r8 
    IL_0013: ldloc.0 
    IL_0014: ldc.i4.0 
    IL_0015: ldelem.i8 
    IL_0016: call  void [mscorlib]System.Console::WriteLine(float64) 
    IL_001b: ret 
} // end of method Foo::Main 

¿Tiene alguna idea?

+0

¿Cómo se ve un fragmento il generado por C#? –

+2

Admito que soy bastante de mala calidad en IL, pero ¿no estás almacenando una referencia de matriz en una variable local de tipo declarado (int/doble)? ¿No debería ese local ser una referencia de algún tipo? –

+0

@Damien_The_Unbeliever: Sí, he cometido un error y he asignado incorrectamente una referencia de matriz en una variable entera. –

Respuesta

6
LocalBuilder arr = gen.DeclareLocal(typeof(int)); 
gen.Emit(OpCodes.Ldc_I4_1); 
gen.Emit(OpCodes.Newarr, typeof(int)); 
gen.Emit(OpCodes.Stloc, arr); 

¿Por qué es el arr no de tipo int[]?

Estoy seguro de que peverify se quejaría por ambas versiones.

El hecho de que se ejecute para la primera versión es simplemente 'suerte' *.

* La razón es mucho más compleja.

+0

Gracias He cometido un GRAN error, el tipo de variable debe ser doble [] Después de cambiar mi código funciona LocalBuilder arr = gen.DeclareLocal (typeof (double [])); Lamentablemente para int [] el ejemplo de matriz funciona con LocalBuilder arr = gen.DeclareLocal (typeof (int)); –

+3

@Upul: La razón es compleja por qué funciona. El sistema ve el 'int' como compatible con un tipo de puntero. Similar a lo que C le permite hacer. – leppie

+0

Estoy en x86 aquí - ¿Supongo que caería en x64? (Además, técnicamente no es una referencia en lugar de un puntero) –

Cuestiones relacionadas