MSIL 中的 [opt] 是什么意思?
我发现 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) Name : a flags: [可选] [ HasDefault] (00001010) Default: (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
方法主体的第二行调用我的自定义属性的构造函数。
所以这引起了我的疑问:
- [opt]是什么意思?我的意思是出现在方法 A 和 B 的参数前面的那个。
- 为什么方法 C 调用应用于其参数的属性的构造函数,而方法 A 和 B 却没有调用?
- 我似乎在元数据中找不到 DefaultParameterValueAttribute 的任何标志,但我可以找到OptionalAttribute 和 MyTestAttribute。这是为什么?我有什么遗漏的吗?
提前致谢。
I found the "optional parameters" feature in C# 4.0 very interesting, so I tried to figure out how they made it happen.
so I wrote a method like this:
private static void A(int a = 5) { }
Compiled it, then decompiled it in IL DASM, this is the IL code:
.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
And it has got this in its metadata:
(1) ParamToken : (08000002) Name : a flags: [Optional] [HasDefault] (00001010) Default: (I4) 5
So I followed the clue and wrote a method like this:
private static void B([Optional, DefaultParameterValue(78)]int b) { }
Compiled it and decompiled it, and I found that the C# compiler generated almost the identical MSIL code for method A and B(except for the name).
As we can see there is no sign of attributes in the IL code and it felt wrong, so I wrote a custom attribute like this:
[AttributeUsage(AttributeTargets.Parameter)]
public class MyTestAttribute : Attribute
{
}
Then used it in method C like this:
private static void C([MyTest]int c) { }
Compiled it and then decompiled it, and hah, I found this:
.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
The second line of the method body calls to the ctor of my custom attribute.
So this leads to my doubts:
- What does [opt] mean? I mean the one that appears in front of method A and B's parameter.
- How come method C calls the constructor of the Attribute that is applied to its parameter and method A and B do not?
- I can not seem to find any sign of DefaultParameterValueAttribute in the metadata, but I can find OptionalAttribute and MyTestAttribute. Why is that? Is there something that I am missing?
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
C# 编译器不需要发出属性,因为 Param 元数据表已经可以通过
Flags
列描述可选值和默认值。从 ECMA 335 中的 23.1.13 开始:
参数可以具有指定它的标志值是可选的并具有默认值 (0x0010 | 0x1000)。具有默认值的参数将在常量元数据表中具有关联的标记。
Constant 元数据表有一个
Parent
列(它是相关的 Param 标记)和一个Value
列(它是存储默认值的 Blob 堆的索引)。因此,回答您的问题:
Flags
列设置了可选标志。The C# compiler doesn't need to emit the attributes since the Param metadata table can already describe optional and default values via the
Flags
column.From 23.1.13 in ECMA 335:
A parameter can have a flag value that specifies it is optional and has a default value (0x0010 | 0x1000). Parameters that have a default value will have an associated token in the Constant metadata table.
The Constant metadata table has a
Parent
column that would be the Param token in question and aValue
column that would be an index into the blob heap where the default value is stored.So to answer your questions:
Flags
column for the Param token has the Optional flag set.2 / 3;有一些属性被编译器解释为 IL 元数据,而不是真正的属性;看起来这里就是这种情况;
[Serialized]
是另一个示例。默认值的数据如下:Default: (I4) 5
- 并非代码中的所有属性都会成为元数据中的属性(同样,我正在查看[Serialized]
这里)关于
[Serialized]
(评论)的那个点;这是一个示例:其核心 IL 是:
在
Foo
中(对于某些任意属性),我们得到:但是这不适用于
[Serializable]
;相反,它是类型的一部分:2 / 3; there are a few attributes that the compiler interprets as IL metadata, not really attributes; it looks like this is the case here;
[Serializable]
is another example. The data for the default is there:Default: (I4) 5
- not all attributes in code become attributes in the metadata (again, I'm looking at[Serializable]
here)re that point on
[Serializable]
(comments); here's an example:for which the core IL is:
In
Foo
(for some arbitrary attribute), we get:However this does not apply for
[Serializable]
; instead, that is part of the type: