2011-03-31 8 views
9

Encontré la característica de "parámetros opcionales" en C# 4.0 muy interesante, así que traté de averiguar cómo lo hicieron posible. así que escribió un método como este:¿Qué significa [opt] en MSIL?

private static void A(int a = 5) { } 

recopiló, a continuación, decompilados en IL DASM, este es el código IL:

.method private hidebysig static void A([opt] int32 a) cil managed 
{ 
    .param [1] = int32(0x00000005) 
    // Code size  2 (0x2) 
    .maxstack 8 
    IL_0000: nop 
    IL_0001: ret 
} // end of method Program::A 

Y se ha conseguido esto en sus metadatos:

(1) ParamToken: (08000002) Nombre: un banderas: [Opcional] [HasDefault] (00001010) por defecto: (I4) 5

Así que siguió a la idea y escribió un método como este:

private static void B([Optional, DefaultParameterValue(78)]int b) { } 

compilado y decompiled ella, y encontró que el compilador de C# genera casi el código MSIL idénticos para el método A y B (excepto para el nombre).

Como podemos ver, no hay ninguna señal de atributos en el código IL y se sentía mal, por lo que escribió un atributo personalizado como esto:

[AttributeUsage(AttributeTargets.Parameter)] 
public class MyTestAttribute : Attribute 
{ 
} 

Luego lo usó en el método C de esta manera:

private static void C([MyTest]int c) { } 

compilado y luego descompilado, y hah, he encontrado este:

.method private hidebysig static void C(int32 c) cil managed 
{ 
    .param [1] 
    .custom instance void ConsoleApplication1.MyTestAttribute::.ctor() = (01 00 00 00) 
    // Code size  2 (0x2) 
    .maxstack 8 
    IL_0000: nop 
    IL_0001: ret 
} // end of method Program::C 

la segunda línea de la El método llama al ctor de mi atributo personalizado.

Así que esto conduce a mis dudas:

  1. Lo que sí [opt] significa? Me refiero al que aparece delante del parámetro del método A y B.
  2. ¿Cómo es que el método C llama al constructor del atributo que se aplica a su parámetro y el método A y B no?
  3. Parece que no puedo encontrar ningún signo de DefaultParameterValueAttribute en los metadatos, pero puedo encontrar OptionalAttribute y MyTestAttribute. ¿Porqué es eso? ¿Hay algo que me falta?

Gracias de antemano.

Respuesta

10

El compilador C# no necesita emitir los atributos ya que la tabla de metadatos Param ya puede describir valores opcionales y predeterminados a través de la columna Flags.

De 23/01/13 en ECMA 335:

Flag   Value Description 
----------------------------------------------------- 
In    0x0001 Parameter is [In] 
Out    0x0002 Parameter is [Out] 
Optional  0x0010 Parameter is optional 
HasDefault  0x1000 Parameter has a default value 
HasFieldMarshal 0x2000 Parameter has FieldMarshal 

Un parámetro puede tener un valor de indicador que especifica que es opcional y tiene un valor por defecto (0x0010 | 0x1000). Los parámetros que tienen un valor predeterminado tendrán un token asociado en la tabla de metadatos de Constant.

La tabla de metadatos de Constant tiene una columna Parent que sería el token de Param en cuestión y una columna Value que sería un índice en el montón de blobs donde se almacena el valor predeterminado.

Así que para responder a sus preguntas:

  1. [opt] significa la columna de la Flags para el token Param tiene establecido el indicador opcional.
  2. Como mencioné anteriormente, supongo que el compilador de C# reconoce los atributos Opcional/DefaultParameterValue y simplemente los convierte en indicadores de parámetros.
  3. Editar: Parece que el compilador de C# está emitiendo un TypeRef no utilizado para OptionalAttribute, a pesar del indicador opcional que se utiliza para el parámetro. Sin embargo, no emite un TypeRef para DefaultParameterValueAttribute. Podría ser un pequeño error del compilador al emitir TypeRefs/MemberRefs sin usar.
+0

Gracias, no esperaba obtener una respuesta tan pronto. Pero el tuyo parece ser el indicado. – CuiPengFei

+0

Y he estado pensando que opt significa optimizado ... – CuiPengFei

+0

Wow, no esperaba encontrar un error de CSC. – CuiPengFei

2

2/3; hay algunos atributos que el compilador interpreta como metadatos IL, no realmente atributos; parece que este es el caso aquí; [Serializable] es otro ejemplo. Los datos para el valor por defecto es no: Default: (I4) 5 - No todos los atributos de código se convierten en atributos en los metadatos (de nuevo, estoy mirando [Serializable] aquí)


volver de ese momento [Serializable] (comentarios); he aquí un ejemplo:

[Description("abc")] 
class Foo { } 

[Serializable] 
class Bar { } 

para el cual el núcleo IL es:

.class private auto ansi beforefieldinit Foo 
    extends [mscorlib]System.Object 
{ 
    .custom instance void [System]System.ComponentModel.DescriptionAttribute::.ctor(string) = { string('abc') } 
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed 
    { 
    } 

} 
.class private auto ansi serializable beforefieldinit Bar 
    extends [mscorlib]System.Object 
{ 
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed 
    { 
    } 

} 

En Foo (por algún atributo arbitrario), obtenemos:

.custom instance void [System]System.ComponentModel.DescriptionAttribute::.ctor(string) = { string('abc') } 

Sin embargo, esto no se aplica para [Serializable]; en cambio, eso es parte del tipo:

.class private auto ansi serializable beforefieldinit Bar 
+1

Gracias, eso explica mucho. Por cierto, vi tu publicación cuando estaba buscando en Google "parámetros opcionales", :) – CuiPengFei

+0

Acabo de probarlo, de hecho, Serializable todavía aparece en la sección de tipo de letra de los metadatos. – CuiPengFei

+0

@CuiPengFei - actualización para ilustrar –