你什么时候使用“this”关键词?[关闭]

When do you use the "this" keyword? [closed]

提问人: 提问时间:8/23/2008 最后编辑:8 revs, 7 users 47%Magic Hat 更新时间:10/12/2018 访问量:227055

问:

已锁定。这个问题及其答案被锁定,因为这个问题偏离了主题,但具有历史意义。它目前不接受新的答案或交互。

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

在构造函数中:

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

别处

public void SomeMethod()
{
    Vector vec = new Vector();
    double d = (vec * vec) - (this.radius * this.radius);
}
C# 编码样式

评论

2赞 Matt 2/18/2014
当你在MSDN真正需要时,我找到了很好的例子。请点击此链接... ;-)this
12赞 djmj 5/29/2014
如果你必须理解和优化或重写其他人,主要是你很乐意拥有的写得很差的代码或任何其他限定符,这样你就可以从简单的外观中知道变量的范围(特别是省略常量的类限定符(相同的包或层次结构)或/限定符)。使用常用的语法对我自己来说似乎并不那么优雅。按智能感知比输入更耗时。何必呢!使用eclipse自动保存格式化功能,无需万一您忘记了限定符。thissuperbase_foo_this_
0赞 Yusha 7/11/2019
在阅读了下面的答案和评论,以及阅读了MSDN文档之后:learn.microsoft.com/en-us/previous-versions/visualstudio/...在6年没有更新的这个关键词上,我建议永远不要使用this这个关键词。这毫无意义。不要使参数同名,这会令人困惑和愚蠢。你为什么要这样做?另外,不要使用它传递实例,这也是令人困惑和愚蠢的。

答:

38赞 Thomas Owens #1

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

评论

0赞 broadband 1/10/2014
我想尽可能多地区分类变量,这样代码就更清晰了。我曾经使用前缀m_(成员变量),例如私有字符串m_name。现在我只是使用它,例如,如果我有类 Test { private string a; public someMethod() { this.a = “foo”;
5赞 TheSmurf #2

我在任何可能有歧义的地方使用它(显然)。不仅是编译器的歧义(在这种情况下是必需的),而且对于查看代码的人来说也是模棱两可的。

1赞 JamesSugrue #3

我倾向于用 _ 在字段下划线,所以真的不需要使用它。此外,R# 无论如何都倾向于重构它们......

3赞 juan #4

您应该始终使用它,我用它来区分私有字段和参数(因为我们的命名约定规定我们不使用前缀作为成员和参数名称(并且它们基于互联网上的信息,因此我认为这是一种最佳实践))

96赞 2 revs, 2 users 97%Corey #5

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

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 指出的那样,当您需要将其作为参数传递时。(局部变量优先于成员变量)

评论

6赞 wz366 5/15/2018
在这种情况下,为什么不给构造函数的输入变量赋予不同的名称呢?
11赞 Ryan Fox #6

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

一个特别方便的场景是,当您的对象正在调用一个函数并希望将自身传递到该函数中时。

例:

void onChange()
{
    screen.draw(this);
}
1赞 akmad #7

我几乎只在从同一类型内部引用类型属性时才使用它。正如另一位用户所提到的,我还在局部字段下划线,因此它们在不需要的情况下就很明显。

0赞 Dan Blair #8

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

7赞 Philippe #9

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

36赞 7 revs, 3 users 56%Jason Bunting #10

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

当存在歧义时,请使用“this”,如 Corey 的示例,或者当您需要将对象作为参数传递时,如 Ryan 的示例。没有理由以其他方式使用它,因为能够基于作用域链解析变量应该足够清晰,以至于没有必要用它限定变量。

编辑:关于“this”的 C# 文档指出,除了我提到的两个之外,“this”关键字还有一种用途 - 用于声明索引器

编辑:@Juan:呵呵,我没有看到我的陈述有任何不一致之处 - 有 3 种情况下我会使用“this”关键字(如 C# 文档中所述),而这些时候是您真正需要它的时候。在没有阴影的情况下,将“this”粘贴在构造函数中的变量前面只是浪费击键和阅读它时浪费时间,它没有任何好处。

评论

21赞 juan 8/23/2008
@JasonBunting:有时你不能做某事,而不能做其他一些事情......这令人困惑......我希望我永远不要在你的代码中工作 你不能总是假设将来阅读你的代码的人会理解你写的内容,你需要尽可能清晰,实现它的一个方法是保持一致
0赞 Scott Adams 6/19/2019
@juan,10年后。你还认为使用“this”是好的做法吗?:)
2赞 juan 6/19/2019
@ScottAdams我仍然相信一致性和清晰度,是的
0赞 BornToCode 6/26/2019
仅通过查看变量(无论是局部变量还是成员变量)来确定变量的范围怎么样?难道“这个”不是有道理的吗?或者你的意思是说,如果我们编写更小的方法,无论如何都很容易理解变量的范围?
27赞 Ian Nelson #11

每当 StyleCop 告诉我时,我都会使用它。必须遵守 StyleCop。哦,是的。

评论

1赞 Gunnar 5/24/2013
ReSharper告诉我不要使用它。当我同时使用 StyleCop 和 ReSharper 时有点令人困惑:)但我倾向于上面 Coreys 的回答,只有在绝对必要时才使用“this”关键字。
0赞 wingerse 2/27/2016
@Gunnar,有一个选项可以禁用 R 中多余的“this”。#
0赞 Gunnar 4/26/2016
@EmperorAiman - 是的,我知道。我的观点是,这两种流行的格式化工具是默认的,暗示了两种不同的东西,这可能会令人困惑。“是还是不是......”:)
245赞 3 revs, 2 users 90%Scott Wisniewski #12

我并不是说这听起来很尖刻,但这并不重要。

认真地。

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

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

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

评论

35赞 Dan Barowy 6/5/2013
关键字在语义上是有意义的。请参阅下面的 @JasonBunting 的评论。你混淆了文体上的过度使用和它的实际目的。你的言论不仅是轻率的,而且是错误的!thisthis
12赞 Scott Wisniewski 6/5/2013
如果有机会,你可能想重新阅读我的答案。我谈论在需要正确语义的情况下使用它。您可能还想查看起源问题。它显示了在语义上没有必要的示例中的用法。所以,我不确定我说的到底是“错的”。我的回答当然不是轻率的。
9赞 Matt 2/5/2014
你知道你的答案对我来说听起来如何吗?在字里行间,我读到“你怎么敢问这样的问题?”——在我看来,这真的没有建设性。没有人知道一切 - 这就是我们拥有 Stackoverflow 的原因:帮助他人并获得帮助。有些主题你知道,有些知道其他主题。互相帮助,不要互相争斗。请考虑一下。
9赞 aioobe 3/15/2015
我并不是要听起来很尖酸刻薄,但这是迄今为止最糟糕的答案之一。我看不出将这与你的工作或个人生活进行比较有什么用。仅仅因为有些事情不如其他事情重要并不意味着它们不重要。拥有一致的编程风格并非不重要(阅读一本关于你选择的代码可读性/可维护性的书)。
4赞 Scott Wisniewski 3/16/2015
我想你可能误解了我的观点。这并不是说“保持一致的风格”是不好的。我什么也没说。而是“我的风格指南是否应该强制要求'this.'作为所有字段访问的前缀?”的操作问题是武断和反复无常的。
217赞 9 revs, 5 users 49%Jakub Šturc #13

关键字在 C# 中有多种用法。

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

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

评论

49赞 Marc Gravell 11/17/2011
8. 在当前实例上调用扩展方法(将起作用,但不会)this.Foo();Foo()
4赞 nawfal 11/14/2013
此外,将自身转换为另一种类型,例如,将调用显式实现的方法,例如。((ICollection<T>)this).Add(bla)
4赞 Lasse V. Karlsen 7/5/2014
将构造链接到在同一类型中定义的另一个构造函数。.public ClassName(...) : this(...)
1赞 phoog 5/6/2015
@Anand它不会影响运行时的性能。假设没有歧义,则无论您是否编写 .这可能会影响编译器的性能,因为编译器会以不同的方式解析源代码,但任何差异肯定可以忽略不计。this.someField = someValuesomeField = someValue
7赞 phoog 5/6/2015
仅当遵循属性不能与参数同名的样式约定时,才可以通过属性访问字段来避免第一个问题。碰巧流行的 C# 样式约定满足了该要求。但是,并非所有 C# 都是根据该约定编写的。属性本身没有任何固有的东西会使关键字变得不必要;调用的构造函数参数将隐藏名为成员的成员,无论该成员是字段、属性还是事件。thisxx
4赞 Vaibhav #14

这是我使用它的时候:

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

我不将其用于私有字段,因为我在私有字段变量名称前面加上下划线 (_)。

54赞 Brandon Wood #15

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

评论

9赞 surfen 12/4/2011
但是,如果您有时忘记使用它,他们会感到困惑
2赞 Maarten Bodewes 1/8/2014
@surfen可以通过额外的样式检查来避免,例如在 Java 中,您可以使用 Checkstyle 并在完整构建后运行它(在任何流行的迭代/OO 语言中都会有类似的工具)
5赞 Askolein 1/21/2014
@surfen好像你在模棱两可的情况下忘记了它。我可以通过说“但如果你忘记了......”来打破任何论点。
6赞 djmj 5/29/2014
大多数人似乎从不阅读、优化或重写别人的代码!预选赛可以节省时间和动力!没有限定符,如果你看到任何任意的代码行,它就像魔术一样。所以你把所有的时间都浪费在检查这些变量的来源上。
3赞 Michael J. 11/4/2016
我知道这是一篇非常古老的帖子,但忍不住评论这个答案的讽刺意味(我碰巧同意)。在反对邪恶的匈牙利符号的圣战中,任何敢于在成员变量前面加上“m_”的人很快就会受到嘲笑,因为区分成员变量是没有用的,也没有必要。
2赞 JohnMcG #16

我养成了在视觉C++中大量使用它的习惯,因为这样做会触发 IntelliSense,我按下了“>”键,我很懒。(并且容易出现错别字)

但是我一直在使用它,因为我发现看到我调用的是成员函数而不是全局函数很方便。

4赞 Nick #17

[C++]

我同意“必要时使用它”旅。用不必要地修饰代码不是一个好主意,因为当你忘记这样做时,编译器不会警告你。这给那些期望它总是存在的人们带来了潜在的困惑,即他们必须考虑

那么,你什么时候会使用它呢?我刚刚浏览了一些随机代码并发现了这些示例(我不是在判断这些是否是好事):

  • 将“yourself”传递给函数。
  • 将“你自己”分配给指针或类似的东西。
  • 铸造,即上/下铸造(安全或其他方式),抛弃恒定性等。
  • 编译器强制消除歧义。
-2赞 dicroce #18

除非绝对必要,否则不应使用“this”。

不必要的冗长会受到惩罚。您应该努力使代码的长度与它需要的长度完全相同,而不是不再。

1赞 Pete Kirkham #19

我只在需要时使用它,除了对称操作,由于单参数多态性,必须将其放入一侧的方法中:

boolean sameValue (SomeNum other) {
   return this.importantValue == other.importantValue;
} 
1赞 Stacker #20

[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;
}
1赞 paercebal #21

this在 C++ 编译器上

如果 C++ 编译器没有立即找到符号,它将以静默方式查找该符号。有时,大多数时候,这很好:

  • 如果未在子类中重载母类,请使用母类的方法。
  • 将一种类型的值提升为另一种类型

但有时,你只是不想让编译器猜测。您希望编译器选取正确的符号,而不是另一个符号。

对我来说,这些时间是我想在方法中访问成员方法或成员变量的时候。我只是不想仅仅因为我写的而不是. 不会编译。printfprintthis->printf

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

这些是我使用 .this

(§) 这对我来说仍然是一种谜,但我现在想知道您在源代码中包含 <windows.h> 标头这一事实是否是所有遗留 C 库符号都会污染您的全局命名空间的原因

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

5赞 Paul Batum #22

this 关键字的另一个罕见的用途是,当您需要从实现类中调用显式接口实现时。下面是一个人为的例子:

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

    object ICloneable.Clone()
    {
        throw new NotImplementedException();
    }
}
3赞 2 revs, 2 users 78%Cyberherbalist #23

在 Jakub Šturc 的回答中,他关于在构造器之间传递数据的 #5 可能需要一些解释。这是在重载构造函数中,并且是必须使用 of 的一种情况。在下面的示例中,我们可以使用默认参数从无参数构造函数调用参数化构造函数。this

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

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

0赞 2 revsMark Ransom #24

我用它来调用 Intellisense,就像 JohnMcG 一样,但完成后我会返回并擦除“this->”。我遵循Microsoft约定,即在成员变量前面加上“m_”,因此将其保留为文档是多余的。

0赞 slim #25

1 - 常见的 Java setter 习语:

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

2 - 调用以此对象为参数的函数时

notifier.addListener(this);
1赞 Jonathan C Dickinson #26

“this.”有助于查找“this”类中具有大量成员的成员(通常是由于较深的继承链)。

按 CTRL+空格键对此无济于事,因为它还包括类型;where-as 'this.' 仅包括成员。

我通常会在拥有我所追求的东西后将其删除:但这只是我的风格突破。

在风格方面,如果你是一个独行侠——你决定;如果你在一家公司工作,请遵守公司政策(看看源代码管理中的东西,看看其他人在做什么)。就用它来限定成员而言,既没有对错之分。唯一错误的是不一致——这是风格的黄金法则。别管吹毛求疵。花时间思考真正的编码问题 - 显然是编码 - 而不是。

1赞 #27

我每次都使用它。我相信它使代码更具可读性,而更具可读性的代码等于更少的错误和更高的可维护性。

1赞 Paw Baltzersen #28

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

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

0赞 David Rodríguez - dribeas #29

在 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>fderived

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

第二种方式,如果您从具有多个参数或长名称的模板继承,则排序器只是在符号前添加一个。由于您正在实现的模板类确实依赖于参数(它继承自 )依赖于参数,因此我们得到相同的结果:在模板参数替换后的第二轮检查。this->base<T>this->this->f

3赞 bobobobo #30

当一个函数接受对相同类型的对象的引用时,我会使用它,我想非常清楚地说明我指的是哪个对象,在哪里。

例如

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

(与)

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

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

一目了然地,AABB指的是哪个?这增加了一点澄清剂。right()this