什么时候用“this”;关键字?

我很好奇其他人是如何使用关键字的。我倾向于在构造函数中使用它,但我也可能在整个类的其他方法中使用它。一些例子:

在构造函数中:

public Light(Vector v)
{
this.dir = new Vector(v);
}

在其他地方

public void SomeMethod()
{
Vector vec = new Vector();
double d = (vec * vec) - (this.radius * this.radius);
}
219621 次浏览

每当我引用一个实例变量时,我都会使用它,即使我不需要。我认为这让代码更清晰。

我在任何可能有歧义的地方都使用它(显然)。不只是编译器的模糊性(在这种情况下是必需的),还有查看代码的人的模糊性。

我倾向于用_来强调字段,所以真的不需要使用这个。r#也倾向于将它们重构掉……

你应该经常使用它,我用它来区分私有字段和参数(因为我们的命名约定声明我们不为成员和参数名使用前缀(并且它们是基于在互联网上找到的信息,所以我认为这是一个最佳实践))

我只在绝对必要的时候使用它,即当另一个变量遮蔽另一个变量时。比如这里:

class Vector3
{
float x;
float y;
float z;


public Vector3(float x, float y, float z)
{
this.x = x;
this.y = y;
this.z = z;
}


}

或者像Ryan Fox指出的,当你需要把它作为参数传递时。(局部变量优先于成员变量)

任何时候需要对当前对象的引用。

一个特别方便的场景是当对象调用一个函数并希望将自己传递给它时。

例子:

void onChange()
{
screen.draw(this);
}

我基本上只在从同一类型中引用类型属性时使用。正如另一个用户提到的,我还强调了本地字段,这样它们就可以被注意到,而不需要

这取决于我所遵循的编码标准。如果我们用_来表示一个实例变量,那么“this”就多余了。如果我们不使用_,那么我倾向于使用这个来表示实例变量。

我也倾向于在任何地方使用它,只是为了确保我们正在处理的是实例成员。

我不能相信所有的人都说使用它总是一个“最佳实践”之类的。

当存在歧义时,如科里的例子或需要将对象作为参数传递时,如瑞安的例子,请使用"this"。没有理由以其他方式使用它,因为能够基于作用域链解析变量应该足够清楚,因此不需要用它来限定变量。

编辑:关于"this"的c#文档指出了"this"关键字除了我提到的两种用法之外的另一种用法——用于声明索引器

编辑:@Juan:嗯,我在我的语句中没有看到任何不一致-有3个实例,当我使用“this”关键字时(如c#文档中所记录的),而那些是你实际上需要它的时候。在构造函数中,当没有阴影发生时,在变量前面加上“this”只是浪费我的击键和阅读它的时间,它没有任何好处。

从来没有。永远。如果你有变量阴影,你的命名约定就会崩溃。我的意思是,成员变量没有区别的命名吗?Facepalm指

我使用它每当StyleCop告诉我。StyleCop必须遵守。噢,是的。

我并不想这么说,但这并不重要。

认真对待。

看看那些重要的东西:你的项目,你的代码,你的工作,你的个人生活。它们中的任何一个都不会成功依赖于是否使用“this”关键字来限定对字段的访问。这个关键字不会帮助你按时发货。它不会减少bug,也不会对代码质量或可维护性产生明显的影响。它不会让你加薪,也不会让你在办公室花更少的时间。

这只是一个风格问题。如果你喜欢“this”,那就用它。如果你不喜欢,那就不要。如果你需要它来获得正确的语义,那么就使用它。事实上,每个程序员都有自己独特的编程风格。这种风格反映了特定程序员对“最美观的代码”应该是什么样子的概念。根据定义,任何其他阅读您代码的程序员都将具有不同的编程风格。这意味着总是会有你做了别人不喜欢的事情,或者会做不同的事情。在某些时候,有些人会阅读您的代码并抱怨一些事情。

我不会为此烦恼。我只会根据您自己的口味确保代码尽可能地美观。如果你问10个程序员如何格式化代码,你会得到大约15个不同的意见。更值得关注的是代码是如何分解的。事物是抽象的吗?我给东西取了有意义的名字吗?有很多代码重复吗?有什么方法可以简化吗?我认为,正确处理这些事情将对您的项目、代码、工作和生活产生最大的积极影响。巧合的是,这可能也会让另一个人抱怨得最少。如果你的代码可以工作,易于阅读,并且分解得很好,那么其他人就不会仔细检查你是如何初始化字段的。他只会使用你的代码,惊叹于它的伟大,然后转向其他东西。

在c#中关键字有几种用法。

  1. 限定由相似名称隐藏的成员
  2. 将对象自身作为参数传递给其他方法
  3. 使对象从方法中返回自身
  4. 声明索引器
  5. 声明扩展方法
  6. 在构造函数之间传递参数
  7. 在内部重新分配值类型(struct)值
  8. 在当前实例上调用扩展方法
  9. 转换为另一种类型
  10. 到同一类中定义的链构造函数

可以通过在作用域中不使用相同名称的成员变量和局部变量来避免第一种用法,例如通过遵循通用命名约定并使用属性(Pascal大小写)而不是字段(驼峰大小写)来避免与局部变量冲突(也是驼峰大小写)。在c# 3.0中,通过使用自动实现的属性可以很容易地将字段转换为属性。

下面是我使用它的时候:

  • 从类内部访问私有方法(以区分)
  • 将当前对象传递给另一个方法(或在发生事件时作为发送者对象)
  • 创建扩展方法时:D

我没有对私有字段使用这个,因为我用下划线(_)作为私有字段变量名的前缀。

就我个人而言,我在引用成员变量时总是尝试使用。它有助于澄清代码并使其更具可读性。即使没有歧义,第一次阅读我的代码的人也不知道这一点,但如果他们看到被一致使用,他们就会知道他们是否在查看成员变量。

我养成了在Visual c++中大量使用它的习惯,因为这样做会触发智能感知,当我按'>'键时,我很懒。(而且容易出现错别字)

但我继续使用它,因为我发现它很方便,可以看到我调用的是成员函数而不是全局函数。

(c++)

我同意“非用不可”的说法。不必要地用修饰代码并不是一个好主意,因为当你忘记这样做时,编译器不会警告你。这为那些期望始终存在的人带来了潜在的困惑,即他们必须对它进行认为

那么,你什么时候会使用它呢?我只是看了一下周围的一些随机代码,并发现了这些例子(我不判断这些是否的事情要做或其他):

  • 将“yourself”传递给一个函数。
  • 将“你自己”分配给一个指针或类似的东西。
  • 铸造,即上/下铸造(安全或其他),铸造constness等。
  • 编译器强制消歧。

除非万不得已,否则不要用this。

不必要的冗长是有惩罚的。您应该努力使代码的长度恰好与需要的长度相同,而不是更长。

我只在需要的时候使用它,除了对称操作,由于单参数多态性不得不把它放在一边的方法中:

boolean sameValue (SomeNum other) {
return this.importantValue == other.importantValue;
}

(c++)

用于赋值操作符,大多数时候你必须检查和防止奇怪的(无意的,危险的,或只是浪费程序时间的)事情,如:

A a;
a = a;

你的赋值操作符将被写成:

A& A::operator=(const A& a) {
if (this == &a) return *this;


// we know both sides of the = operator are different, do something...


return *this;
}

c++编译器上的this

如果c++编译器没有立即找到一个符号,它会默默地查找。有时候,大多数时候,这是好的:

  • 如果在子类中没有重载母类的方法,则使用母类的方法。
  • 将一个类型的值提升为另一个类型

但有时,你只是不想让编译器猜测。您希望编译器提取正确的符号,而不是其他符号。

对我来说,这些时间是当,在一个方法中,我想访问一个成员方法或成员变量。我只是不想因为我写了printf而不是print而捡到一些随机的符号。this->printf将无法编译。

关键是,对于C遗留库(§),多年前编写的遗留代码(§§),或者在复制/粘贴已经过时但仍然活跃的语言中可能发生的任何事情,有时,告诉编译器不要耍花招是一个好主意。

这些是我使用this的原因。

(§)这对我来说仍然是一个谜,但我现在想知道你是否包括<窗户。头文件,是所有遗留的C库符号会污染全局命名空间的原因

(§§)意识到“你需要包含一个头文件,但是包含这个头文件会破坏你的代码,因为它使用了一些具有通用名称的愚蠢宏”是一个编码器生命中的俄罗斯轮盘赌时刻之一

this关键字的另一个很少使用的情况是,当您需要从实现类中调用显式接口实现时。这里有一个人为的例子:

class Example : ICloneable
{
private void CallClone()
{
object clone = ((ICloneable)this).Clone();
}


object ICloneable.Clone()
{
throw new NotImplementedException();
}
}

在Jakub Šturc的回答中,他关于在构造器之间传递数据的第5条可能需要一些解释。这是在重载构造函数中,也是强制使用this的一种情况。在下面的例子中,我们可以使用默认形参从无参数构造函数调用参数化构造函数。

class MyClass {
private int _x
public MyClass() : this(5) {}
public MyClass(int v) { _x = v;}
}

我发现有时候这是一个特别有用的功能。

我使用它来调用智能感知,就像JohnMcG一样,但当我完成时,我会返回并删除“this->”。我遵循微软的惯例,在成员变量前加上“m_”,所以把它作为文档是多余的。

1 -常见的Java setter习语:

 public void setFoo(int foo) {
this.foo = foo;
}

2 -当调用以该对象作为参数的函数时

notifier.addListener(this);

“这。'帮助查找'this'类中有很多成员的成员(通常是由于深度继承链)。

按CTRL+空格键并没有帮助,因为它还包括类型;而这。’只包括会员。

一旦我得到我想要的东西,我通常会删除它:但这只是我风格的突破。

在风格方面,如果你是一个独行侠——你决定;如果你在一家公司工作,坚持公司的政策(看看源代码控制中的东西,看看其他人在做什么)。就用它来评定成员资格而言,既不正确也不错误。唯一错误的就是前后矛盾——这是风格的黄金法则。别挑剔别人。把时间花在思考真正的编码问题上——当然还有编码。

我一有机会就用。我相信这会使代码更有可读性,而更有可读性的代码就等于更少的bug和更强的可维护性。

当你有很多开发人员在同一个代码库上工作时,你需要一些代码指南/规则。在我工作的地方,我们决定在字段、属性和事件上使用“this”。

对我来说,这样做很有意义,当你区分类变量和方法变量时,它使代码更容易阅读。

c++中还有一种用法没有提到,那就是不引用自己的对象,也不从接收到的变量中消除成员的歧义。

你可以使用this在从其他模板继承的模板类中将一个非依赖的名称转换为依赖参数的名称。

template <typename T>
struct base {
void f() {}
};


template <typename T>
struct derived : public base<T>
{
void test() {
//f(); // [1] error
base<T>::f(); // quite verbose if there is more than one argument, but valid
this->f(); // f is now an argument dependent symbol
}
}

模板是用两遍机制编译的。在第一次传递过程中,只解析和检查非参数相关的名称,而仅检查相关名称的一致性,而不实际替换模板参数。

在这一步,没有实际替换类型,编译器几乎没有base<T>可能是什么的信息(注意,基本模板的特化可以将其转换为完全不同的类型,甚至是未定义的类型),所以它只是假设它是一个类型。在这个阶段,对程序员来说很自然的非依赖调用f是编译器必须作为derived的成员或在封闭的名称空间中找到的符号——这在示例中没有发生——并且它会报错。

解决方案是将非依赖名称f转换为依赖名称。这可以通过几种方式来实现,通过显式地声明它实现的类型(base<T>::f——添加base<T>使符号依赖于T,编译器只会假设它存在,并在参数替换之后推迟第二次传递的实际检查。

第二种方法,如果你继承的模板有一个以上的参数,或长名称,排序更简单,只是在符号之前添加this->。由于你实现的模板类确实依赖于实参(它继承自base<T>), this->依赖于实参,我们得到了相同的结果:在模板形参替换之后的第二轮检查this->f

当在一个接受同一类型对象引用的函数中,我想让它完全清楚我所引用的对象,where。

例如

class AABB
{
// ... members
bool intersects( AABB other )
{
return other.left() < this->right() &&
this->left() < other.right() &&


// +y increases going down
other.top() < this->bottom() &&
this->top() < other.bottom() ;
}
} ;

(vs)

class AABB
{
bool intersects( AABB other )
{
return other.left() < right() &&
left() < other.right() &&


// +y increases going down
other.top() < bottom() &&
top() < other.bottom() ;
}
} ;

right()指的是哪个AABB ?this增加了一点澄清。