我发现C#4.0中的“可选参数”功能非常有趣,所以我试图弄清楚它们是如何实现的。 所以我写了一个像这样的方法:
private static void A(int a = 5) { }
编译它,然后在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
它的元数据中有这个:
(1)ParamToken:(08000002)姓名:a flags:[可选] [HasDefault](00001010)默认值:(I4)5
所以我按照线索写了一个像这样的方法:
private static void B([Optional, DefaultParameterValue(78)]int b) { }
编译并反编译它,我发现C#编译器为方法A和B生成了几乎相同的MSIL代码(名称除外)。
正如我们所看到的,IL代码中没有属性的迹象,而且感觉不对,所以我写了一个这样的自定义属性:
[AttributeUsage(AttributeTargets.Parameter)]
public class MyTestAttribute : Attribute
{
}
然后在方法C中使用它,如下所示:
private static void C([MyTest]int c) { }
编译它然后反编译它,哈哈,我发现了这个:
.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
方法体的第二行调用我的自定义属性的ctor。
所以这引起了我的怀疑:
提前致谢。
答案 0 :(得分: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
参数可以有一个标志值,指定它是可选的,并且具有默认值(0x0010 | 0x1000)。具有默认值的参数将在常量元数据表中具有关联的标记。
常量元数据表有一个Parent
列,它将是所讨论的Param令牌,以及一个Value
列,它将成为存储默认值的blob堆的索引。
所以回答你的问题:
Flags
列设置了可选标志。答案 1 :(得分:2)
2/3;编译器将一些属性解释为IL元数据,而不是真正的属性;看起来这就是这种情况; [Serializable]
是另一个例子。默认的数据是:Default: (I4) 5
- 并非代码中的所有属性都成为元数据中的属性(同样,我在这里看[Serializable]
)
重点[Serializable]
(评论);这是一个例子:
[Description("abc")]
class Foo { }
[Serializable]
class Bar { }
核心IL是:
.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
{
}
}
在Foo
(对于某些任意属性)中,我们得到:
.custom instance void [System]System.ComponentModel.DescriptionAttribute::.ctor(string) = { string('abc') }
但这不适用于[Serializable]
;相反,这是类型的一部分:
.class private auto ansi serializable beforefieldinit Bar