我有一个静态类,其中包含如下所示的静态方法:
public static StaticTest
{
public static void DoSomeWork()
{
/// Do Some work
}
}
当调用DoSomeWork()
函数时,CLR如何管理函数引用,因为静态类的实例显然无法创建?
在这种情况下,背后的机制是什么来调用函数?
我有一个静态类,其中包含如下所示的静态方法:
public static StaticTest
{
public static void DoSomeWork()
{
/// Do Some work
}
}
当调用DoSomeWork()
函数时,CLR如何管理函数引用,因为静态类的实例显然无法创建?
在这种情况下,背后的机制是什么来调用函数?
假设你有以下内容:
class Foo
{
public void Bar()
{
// instance
}
public static void Fiz()
{
// instance
}
}
而你需要做的是:
var temp = new Foo();
Foo.Fiz();
temp.Bar();
你的代码被翻译成了类似以下内容:
var temp = new Foo();
Foo.Fiz();
Foo.Bar(temp);
this是类的隐藏参数(第一个参数)。在Intel的C++中,这被称为thiscall调用约定。对于静态函数,根本就没有此参数。
如果您在代码上打开反汇编功能,您会看到它类似于:
var temp = new Foo();
00007FFBD48042EC lea rcx,[7FFBD48563D8h]
00007FFBD48042F3 call 00007FFC33E42400
00007FFBD48042F8 mov qword ptr [rsp+2B0h],rax
00007FFBD4804300 mov rax,qword ptr [rsp+2B0h]
00007FFBD4804308 mov qword ptr [rsp+2B8h],rax
00007FFBD4804310 mov rcx,qword ptr [rsp+2B8h]
00007FFBD4804318 call 00007FFBD46ECA48
00007FFBD480431D mov r11,qword ptr [rsp+2B8h]
00007FFBD4804325 mov qword ptr [rsp+30h],r11
Foo.Fiz();
00007FFBD480432A call 00007FFBD46ECA40
temp.Bar();
00007FFBD480432F mov r11,qword ptr [rsp+30h]
00007FFBD4804334 cmp byte ptr [r11],0
00007FFBD4804338 mov rcx,qword ptr [rsp+30h]
00007FFBD480433D call 00007FFBD46ECA38
正如您所看到的,Foo.Fiz
是一个直接的 call 00007FFBD46ECA40
,而 temp.bar()
首先会检查 null
(我认为是通过 mov
+ cmp
实现),然后将引用放入 rcx
并执行 call
。
public void DoSomething()
{
InstanceClass objectInstance = new InstanceClass();
objectInstance.MethodName();
StaticClass.MethodName();
// i.e.here clr creates Type Objects for Instance class and StaticClass in the heap
}
当使用new
运算符创建一个类的对象时,CLR会自动在该类的实例中创建一个类型对象指针,并将其初始化为引用相应的类型对象。objectInstance.MethodName()
,CLR根据使用的变量类型识别类型对象,并在类型对象的方法表中查找方法,然后JIT该方法。StaticTest.DoSomeWork()
,CLR(JIT编译器)将根据类名识别静态类的“类型对象”,并在相应的类型对象的方法表中查找方法,然后JIT该方法。call void[assembly]StaticTest:DoSomeWork()
class
引用来调用它,因为static
类无法实例化。就像这样StaticTest.DoSomeWork()
。 - Dhrumil