[英]Calling methods on value types
如果我在这里弄错了,请阻止我。
如果我理解正确,当我在类的实例上调用方法时,JIT编译器将找到与实例类型相对应的类型对象,然后在其中找到实际方法代码的引用。
我的问题是这对价值类型有何影响? 我的印象是值类型没有像引用类型那样的类型对象指针。 如果是这种情况,CLR如何在调用方法时设法导航到方法代码?
考虑一个例子,假设我们有以下结构:
public struct Test
{
public void TestMethod()
{
}
}
这是它的IL代码:
.class public sequential ansi sealed beforefieldinit ConsoleApplication.Test
extends [mscorlib]System.ValueType
{
.pack 0
.size 1
.method public hidebysig
instance void TestMethod () cil managed
{
// Method begins at RVA 0x21dc
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method Test::TestMethod
}
好的,现在因为C#编译器静态地知道Test
的类型,它可以进行重载解析并找到被调用的确切TestMethod
。 然后它发出MSIL以将参数推送到MSIL虚拟堆栈,它需要一个指向Test
的类型指针的参数,编译器在没有装箱的情况下处理它并发出包含对该特定方法的元数据引用的调用指令。
.locals init (
[0] valuetype ConsoleApplication.Test test
)
IL_0000: ldloca.s test
IL_0002: initobj ConsoleApplication.Test
IL_0008: ldloca.s test
IL_000a: call instance void ConsoleApplication.Test::TestMethod()
对于ToString
和GetHashCode
,编译器使用Constrained OpCode ,因为这些方法可以重载。
IL_0002: initobj ConsoleApplication.Test
IL_0008: ldloca.s test
IL_000a: constrained. ConsoleApplication.Test
IL_0010: callvirt instance int32 [mscorlib]System.Object::GetHashCode()
受约束的操作码允许IL编译器以统一的方式调用虚函数,而与ptr是值类型还是引用类型无关。 使用约束前缀还可以避免值类型的潜在版本控制问题。 如果未使用约束前缀,则必须发出不同的IL,具体取决于值类型是否覆盖System.Object的方法。 例如,如果值类型V覆盖Object.ToString()方法,则会发出调用V.ToString()指令; 如果没有,则发出一个box指令和一个callvirt Object.ToString()指令。 如果稍后删除覆盖,则在前一种情况下可能出现版本控制问题,而在后一种情况下,如果稍后添加覆盖则会出现版本控制问题。
对于GetType
方法需要装箱,因为它是非虚拟的并且在Object
类型中定义。
IL_0002: initobj ConsoleApplication.Test
IL_0008: ldloc.0
IL_0009: box ConsoleApplication.Test
IL_000e: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.