[opt]在MSIL中意味着什么?

Cui*_*崔鹏飞 9 .net c# il cil c#-4.0

我发现C#4.0中的"可选参数"功能非常有趣,所以我试图弄清楚它们是如何实现的.所以我写了一个像这样的方法:

private static void A(int a = 5) { }
Run Code Online (Sandbox Code Playgroud)

编译它,然后在IL DASM中反编译它,这是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
Run Code Online (Sandbox Code Playgroud)

它的元数据中有这个:

(1)ParamToken:(08000002)名称:标志:[可选] [HasDefault](00001010)默认值:(I4)5

所以我按照线索写了一个像这样的方法:

private static void B([Optional, DefaultParameterValue(78)]int b) { }
Run Code Online (Sandbox Code Playgroud)

编译并反编译它,我发现C#编译器为方法A和B生成了几乎相同的MSIL代码(名称除外).

正如我们所看到的,IL代码中没有属性的迹象,而且感觉不对,所以我写了一个这样的自定义属性:

[AttributeUsage(AttributeTargets.Parameter)]
public class MyTestAttribute : Attribute
{
}
Run Code Online (Sandbox Code Playgroud)

然后在方法C中使用它,如下所示:

private static void C([MyTest]int c) { }
Run Code Online (Sandbox Code Playgroud)

编译它然后反编译它,哈哈,我发现了这个:

.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
Run Code Online (Sandbox Code Playgroud)

方法体的第二行调用我的自定义属性的ctor.

所以这引起了我的怀疑:

  1. [opt]是什么意思?我的意思是出现在方法A和B的参数前面的那个.
  2. 为什么方法C调用应用于其参数的属性的构造函数,方法A和B不调用?
  3. 我似乎无法在元数据中找到DefaultParameterValueAttribute的任何符号,但我可以找到OptionalAttribute和MyTestAttribute.这是为什么?有什么东西我错过了吗?

提前致谢.

Pet*_*ene 10

C#编译器不需要发出属性,因为Param元数据表已经可以通过Flags列描述可选值和默认值.

从ECMA 335的 23.1.13开始:

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  
Run Code Online (Sandbox Code Playgroud)

参数可以有一个标志值,指定它是可选的,并且具有默认值(0x0010 | 0x1000).具有默认值的参数将在Constant元数据表中具有关联的标记.

Constant元数据表有一个Parent列,它将是有问题的Param标记,以及一个Value列,它将作为存储默认值的blob堆的索引.

那么回答你的问题:

  1. [opt]表示FlagsParam令牌的列具有Optional标志集.
  2. 正如我上面所说,我的猜测是C#编译器识别Optional/DefaultParameterValue属性并简单地将它们转换为参数标志.
  3. 编辑:看起来C#编译器正在为OptionalAttribute发出一个未使用的TypeRef,尽管可选标志用于参数.但是,它不会为DefaultParameterValueAttribute发出TypeRef.它可能是一个小的编译器错误,用于发出未使用的TypeRefs/MemberRefs.