当使用“this”关键字时,系统如何知道使用什么?
最近,我在一次采访中被问到这个问题。从来没有考虑过这一点,我回复说系统将知道控制流所在的当前上下文,并决定要使用的对象而不是这个。面试官看起来不太高兴,他继续下一个问题。
谁能告诉我面试官可能想问什么,答案是什么?(我认为这可以用不同的方式解释,因此除非有人指出不这样做,否则将其保留为 wiki。)
尽管指出“this”引用本质上作为魔术“隐藏参数”传递给调用的答案基本上是正确的,但 C# 中的完整故事实际上比乍一看要复杂得多。
引用类型很简单;检查引用的对象是否为空,然后在概念上将其作为名为“this”的未命名、非变量参数传递。这个故事因值类型而变得复杂。
请记住,根据定义,值类型是按值传递的——也就是说,通过复制数据来传递。因此他们的名字。但显然可变值类型——它们是纯粹的邪恶,应该避免——不能作为“this”通过值传递,因为如果你调用了一个 mutator,mutator 方法中的“this”将改变副本,而不是原本的!
因此,在值类型的方法调用中,“this”不是接收者的值,而是代表接收者存储位置的变量的别名。我们通过传递“this”作为接收者的托管地址来实现这一点,而不是接收者的值。
现在我们可以提出另一个困难。如果存储被变异值的变量是只读变量怎么办?现在我们该怎么办?如果您好奇,请阅读我关于该主题的文章,看看您是否能正确回答所提出的难题:
http://blogs.msdn.com/ericlippert/archive/2008/05/14/mutating-readonly-structs.aspx
this
关键字是指向当前对象的指针。类的所有非静态成员函数都可以访问 this 指针。
指向当前对象的指针通常由编译器通过使用寄存器(通常是 ECX)在非静态成员函数中提供。因此,当您编写this
非静态成员函数时,编译器会将该调用转换为从 ECX 加载地址。
检查这个简单的例子:
在; t.Test(); 004114DE lea ecx,[t] 004114E1 调用 std::operator > (41125Dh)
在调用非静态成员函数之前Test()
,编译器使用 [t] 加载寄存器 ECX(变量 t 的地址 - 将this
在 Test 方法中)。
004114DE lea ecx,[t]
在函数内部,它可以使用 ecx 来获取当前对象实例的地址。
this
是对象所有方法中的隐藏参数,包含实例指针的副本。
考虑这个类
class A {
private:
int data;
public:
void SetData(int arg) {
this->data = arg;
}
}
以及调用 SetData() 的代码:
A objA;
objA.SetData(1);
编译上述代码时,编译器会为成员函数发出与此等效的内容:
void SetData(A* this, int arg) {
this->data = arg;
}
并且调用代码被转换成这样的:
A objA;
SetData(&objA, 1);
这意味着在编译时:
成员函数被转换为简单的全局函数。
成员函数“所属”的类实例只是作为第一个参数传递给它们(或者更确切地说是传递它的地址)。
因此,总而言之,您在代码中称为 this 指针的内容只是作为函数的第一个参数结束。这就是“系统知道”通过“this”指针访问哪个对象的方式。
上面的例子是 C++ 的。如果您暂时忘记了 CLR 和 JITting 以及所有这些,那么 C# 中发生的事情在概念上是相同的。
在运行时“this”将解析为指向当前对象的指针,因此“系统”将能够调用该对象上的相应方法。
我会回答“它是对当前类实例的引用”。
担
编译器负责在编译时正确解析该引用。如果你想了解更多关于他们使用的一些技术的信息,这本书会告诉你你需要知道的一切:
http ://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools
在 c 中,this 指针是指向您的类的不可见指针参数。
所以本质上,类方法的第一个参数是指向类本身的指针。您可以使用它来引用它。
Shematicaly 编译器会转换这样的代码:
pObject->someMethod(A,B,C)
如果“someMethod”不是虚拟的,则进入此类代码:
someMethod(pObject,A,B,C)
如果'someMethod'是虚拟的,或者进入这样的代码:
(*pObject->vtable[someMethodIndex]) (pObject, A,B,C)
并且在您放置“this”关键字的任何地方都使用第一个参数来代替它;
当然,编译器可以通过删除第一个参数并使用一些 CPU 寄存器(通常是 esx)来存储对象的地址来优化/简化。
我的回答是“谁在乎?它知道。如果我需要更详细的信息,我会用谷歌搜索。”
您显然知道使用“this”会产生什么效果,这肯定是重要的事情。对于 99% 的编程任务,我会认为如何在内部解决它的细节是琐事。
“this”运算符将指向当前对象。“this”运算符的存在将产生影响的示例如下:
public class MyClass
{
int value;
public void Test(int value)
{
MessageBox.Show(value); // Will show the parameter to the function
MessageBox.Show(this.value); // Will show the field in the object
}
}
请注意,如果“this”运算符在子类中被覆盖,则不会更改将调用的虚函数
public class MyClass
{
public virtual void Test() {}
public void CallTest()
{
this.Test();
}
}
public class MyClass2 : MyClass
{
public override void Test() {}
}
如果执行以下代码
MyClass c = new MyClass2();
c.CallTest();
仍将调用 MyClass2.Test() 而不是 MyClass.Test()
所以“this”操作符只是告诉你,你正在访问在类级别声明的东西。