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.
所以这引起了我的怀疑:
提前致谢.
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堆的索引.
那么回答你的问题:
FlagsParam令牌的列具有Optional标志集.