Uso de metadatos en tiempo de ejecución
Para comprender mejor los metadatos y su uso en Common Language Runtime, puede resultar útil construir un programa sencillo y mostrar cómo afectan los metadatos a su comportamiento durante su ejecución. El siguiente ejemplo de código muestra dos métodos dentro de una clase llamada MyApp. El método Main es el punto de entrada del programa, mientras que el método Add simplemente devuelve la suma de dos argumentos de enteros.
Public Class MyApp
Public Shared Sub Main()
Dim ValueOne As Integer = 10
Dim ValueTwo As Integer = 20
Console.WriteLine("The Value is: {0}", Add(ValueOne, ValueTwo))
End Sub
Public Shared Function Add(One As Integer, Two As Integer) As Integer
Return (One + Two)
End Function
End Class
using System;
public class MyApp
{
public static int Main()
{
int ValueOne = 10;
int ValueTwo = 20;
Console.WriteLine("The Value is: {0}", Add(ValueOne, ValueTwo));
return 0;
}
public static int Add(int One, int Two)
{
return (One + Two);
}
}
Cuando se ejecuta el código, el motor en tiempo de ejecución carga el módulo en la memoria y consulta los metadatos de esta clase. Una vez cargado, el motor en tiempo de ejecución realiza una análisis exhaustivo de la secuencia de lenguaje intermedio de Microsoft (MSIL) del método para convertirla en rápidas instrucciones máquina nativas. El motor en tiempo de ejecución usa un compilador Just-In-Time (JIT) para convertir las instrucciones MSIL en código máquina nativo, método a método, según sea necesario.
En el siguiente ejemplo de código se muestra parte del MSIL producido a partir de la función Main del código anterior. El MSIL y los metadatos se pueden ver desde cualquier aplicación de .NET Framework usando el Desensamblador de MSIL (Ildasm.exe).
.entrypoint
.maxstack 3
.locals ([0] int32 ValueOne,
[1] int32 ValueTwo,
[2] int32 V_2,
[3] int32 V_3)
IL_0000: ldc.i4.s 10
IL_0002: stloc.0
IL_0003: ldc.i4.s 20
IL_0005: stloc.1
IL_0006: ldstr "The Value is: {0}"
IL_000b: ldloc.0
IL_000c: ldloc.1
IL_000d: call int32 ConsoleApplication.MyApp::Add(int32,int32) /* 06000003 */
El compilador JIT lee el MSIL de todo el método, lo analiza exhaustivamente y genera instrucciones nativas efectivas para ese método. En IL_000d se encuentra un símbolo de metadatos del método Add (/* 06000003 */), y el motor en tiempo de ejecución usa dicho símbolo para consultar la tercera fila de la tabla MethodDef.
En la siguiente tabla se muestra parte de la tabla MethodDef a la que hace referencia el símbolo de los metadatos que describe el método Add. Aunque existen otras tablas de metadatos en el ensamblado y tienen sus propios valores únicos, sólo se trata esta tabla.
Fila |
Dirección relativa virtual (RVA) |
ImplFlags |
Marcadores |
Nombre (señala el montón de cadenas). |
Firma (señala el montón de objetos binarios) |
---|---|---|---|---|---|
1 |
0x00002050 |
IL Administrado |
Public ReuseSlot SpecialName RTSpecialName .ctor |
.ctor (constructor) |
|
2 |
0x00002058 |
IL Administrado |
Public Static ReuseSlot |
Main |
String |
3 |
0x0000208c |
IL Administrado |
Public Static ReuseSlot |
Agregar |
int, int, int |
Cada columna de la tabla contiene información importante sobre el código. La columna RVA permite que el motor en tiempo de ejecución calcule la dirección de memoria de inicio del MSIL que define este método. Las columnas ImplFlags y Flags contienen máscaras de bits que describen el método (por ejemplo, si el método es público o privado). La columna Nombre indiza el nombre del método del montón de cadenas. La columna Firma indiza la definición de la firma del método del montón de objetos binarios.
El motor en tiempo de ejecución calcula la dirección de desplazamiento deseada desde la columna RVA de la tercera fila y la devuelve al compilador JIT, que, a continuación, se dirige a la nueva dirección. El compilador JIT continúa procesando el MSIL en la nueva dirección hasta que encuentra otro símbolo de metadatos y se repite el proceso.
Usando metadatos, el motor en tiempo de ejecución tiene acceso a toda la información que necesita para cargar el código y procesarlo en instrucciones máquina nativas. De este modo, los metadatos hacen posible los archivos autodescriptivos y, junto con el sistema de tipos comunes, la herencia de un lenguaje a otro.