关于c#编译器如何发出TypeRef信息的问题

本文关键字:信息 问题 TypeRef 何发出 编译器 关于 | 更新日期: 2023-09-27 17:50:15

当我在尝试c# 4.0的新特性"可选参数"时,我发现了这个有趣的事情。

我知道在c# 4.0中有两种使用"可选参数"的方法:
static void TestMethod(int parameter = 5) { }
static void TestMethod2([Optional, DefaultParameterValue(5)]int parameter) { }

现在,如果我编译这段代码,然后使用IL Dasm查看程序集,那么我将看到在IL Dasm的"MetaInfo"窗口中,有一个对OptionalAttribute的类型引用,如下所示:

Token:             0x01000002
ResolutionScope:   0x23000001
TypeRefName:       System.Runtime.InteropServices.OptionalAttribute
MemberRef #1 (0a000001)
-------------------------------------------------------
    Member: (0a000001) .ctor: 
    CallCnvntn: [DEFAULT]
    hasThis 
    ReturnType: Void
    No arguments.

但是没有DefaultParameterValueAttribute的迹象。为什么呢?

实际上我认为这两个属性都不应该在这里,因为它们被编译器不同地对待,它们有自己的标志值。为了解释我的意思,请看下面这个:

    Method #2 (06000002) 
-------------------------------------------------------
    MethodName: TestMethod (06000002)
    Flags     : [Private] [Static] [HideBySig] [ReuseSlot]  (00000091)
    RVA       : 0x00002053
    ImplFlags : [IL] [Managed]  (00000000)
    CallCnvntn: [DEFAULT]
    ReturnType: Void
    1 Arguments
        Argument #1:  I4
    1 Parameters
        (1) ParamToken : (08000002) Name : parameter flags: [Optional] [HasDefault]  (00001010) Default: (I4) 5
Method #3 (06000003) 
-------------------------------------------------------
    MethodName: TestMethod2 (06000003)
    Flags     : [Private] [Static] [HideBySig] [ReuseSlot]  (00000091)
    RVA       : 0x00002056
    ImplFlags : [IL] [Managed]  (00000000)
    CallCnvntn: [DEFAULT]
    ReturnType: Void
    1 Arguments
        Argument #1:  I4
    1 Parameters
        (1) ParamToken : (08000003) Name : parameter flags: [Optional] [HasDefault]  (00001010) Default: (I4) 5

这是两个方法的元数据。我们可以看到,每个代码段的最后一行已经存储了默认参数值,那么为什么OptionalAttribute仍然被引用呢?

关于c#编译器如何发出TypeRef信息的问题

这可以被认为是编译器中的错误。如果您仔细检查程序集,就会发现没有任何东西引用了OptionalAttribute TypeRef。

如果不显式地添加TestMethod2,则TypeRef将不会出现在结果程序集中。这仅仅表明属性是在第一次传递中添加的,然后被删除。它还显示了编译器对DefaultParameterValueAttribute的处理方式不同。

最终,这确实是一个很小的实现细节,例如,Mono的c#编译器不会为结果程序集中的两个属性生成TypeRef。