当使用'this'关键字时,系统如何知道要使用什么?

时间:2009-08-21 14:51:12

标签: c# this

当使用'this'关键字时,系统如何知道要使用什么?

最近,我在接受采访时被问到这个问题。从来没有想过这个,我回复说,系统将知道控制流的当前上下文,并决定使用的对象而不是这个。面试官看起来并不高兴,他继续谈到下一个问题。

有谁能告诉我面试官可能想问什么,答案是什么? (我认为这可以用不同的方式解释,因此保持这个维基,除非有人指出不要......)

11 个答案:

答案 0 :(得分:13)

虽然指出“this”引用本质上作为一个神奇的“隐藏参数”传递给答案的答案基本上是正确的,但实际上C#的完整故事比起初想的要复杂得多。一目了然。

参考类型很简单;检查引用的对象是否为null,然后在概念上将其作为未命名的非变量参数传递,称为“this”。这个故事因价值类型而变得复杂。

请记住,根据定义,值类型是按值传递的 - 也就是说,通过制作数据副本来传递。因此他们的名字。但显然可变的值类型 - 纯粹的邪恶并且应该避免 - 不能通过值作为“this”传递,因为如果你调用mutator,mutator方法中的“this”将改变副本,而不是原本的!

因此,在值类型的方法调用中,“this”不是接收器的,它是表示接收器存储位置的变量的别名。我们通过将“this”作为接收者的托管地址而不是接收者的来实现这一点。

现在我们可以提出另一个困难。如果存储被突变值的变量是只读变量,该怎么办?现在我们做什么?如果你很好奇,请阅读我关于这个主题的文章,看看你是否能正确回答所提出的难题:

http://blogs.msdn.com/ericlippert/archive/2008/05/14/mutating-readonly-structs.aspx

答案 1 :(得分:12)

this关键字是指向当前对象的指针。 的所有非静态成员函数都可以访问此指针。

编译器通常使用寄存器(通常为ECX)在非静态成员函数中提供指向当前对象的指针。因此,当您在非静态成员函数中编写this时,编译器会将该调用转换为从ECX加载地址。

检查这个简单的例子:

A t;
t.Test();
004114DE  lea         ecx,[t] 
004114E1  call        std::operator > (41125Dh) 

在调用非静态成员函数Test()之前,编译器使用[t]加载寄存器ECX(变量t的地址 - 将在Test方法中为this

004114DE  lea         ecx,[t]

在函数内部,它可以使用ecx获取当前对象实例的地址。

答案 2 :(得分:9)

this是对象所有方法中的隐藏参数,包含实例指针的副本。

答案 3 :(得分:2)

考虑这个课程

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);

这意味着在编译时:

  1. 成员函数转换为简单的全局函数。

  2. 成员函数“属于”的类实例只是作为第一个参数传递给它们(或者它的地址被传递)。

  3. 总而言之,您在代码中称为此指针的内容只是该函数的第一个参数。这就是“系统知道”通过“this”指针访问哪个对象的方式。

    上面的例子是C ++。如果你暂时忘记了CLR和JITting以及所有这些,C#中发生的事情在概念上是相同的。

答案 4 :(得分:1)

在运行时“this”将解析为指向当前对象的指针,因此“系统”将能够在该对象上调用相应的方法。

答案 5 :(得分:1)

我会回答“它是对当前类实例的引用。”

答案 6 :(得分:1)

编译器负责在编译时正确解析该引用。如果您想了解有关他们用于执行此操作的一些技术的更多信息,本书将告诉您需要了解的所有信息:
http://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools
The Dragon Book

答案 7 :(得分:0)

在c中,this指针是类的不可见指针参数。

因此,本质上,类方法的第一个参数是指向类本身的指针。你可以用它来引用它。

答案 8 :(得分:0)

Shematicaly编译器会转换此类代码:

pObject->someMethod(A,B,C)

如果'someMethod'不是虚拟的话,进入这样的代码:

someMethod(pObject,A,B,C) 

如果'someMethod'是虚拟的话,或者进入这样的代码:

(*pObject->vtable[someMethodIndex]) (pObject, A,B,C)

在任何地方,您都会使用'this'关键字第一个参数来代替它;

当然编译器可以通过删除第一个参数来优化/简化,并使用一些CPU寄存器(通常是esx)来存储对象的地址。

答案 9 :(得分:0)

我的答案是“谁在乎?它知道。如果我需要更详细地了解我会谷歌它。”

你显然知道使用“this”的效果是什么,这肯定是重要的。对于99%的编程任务,我认为内部解决方法的细节是琐事。

答案 10 :(得分:0)

“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”运算符只是告诉你,你正在访问在类级别声明的东西。