您何时使用“ this”关键字?[关闭]


249

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

在构造函数中:

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

别处

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

2
当您真正需要 this MSDN 时,我找到了很好的例子。请点击此链接 ... ;-)
马特(Matt)

12
如果您必须了解,优化或重写其他人(通常写得不好的代码,您会很乐意拥有this或使用任何其他限定符,以便从简单的外观就可以知道变量的范围(特别是常量的类限定符(相同的包或等级)或super/ base限定词)。而且使用像这样的常用语法_foo对于我自己来说似乎并不那么优雅。按下_智能提示比输入更耗时this。还有为什么要打扰呢!使用eclipse自动保存格式设置功能_,以防万一您忘记了限定符。
djmj 2014年

在阅读以下答案和评论以及阅读MSDN文档后:docs.microsoft.com/en-us/previous-versions/visualstudio/…关于关键字的使用已经6年没有更新了,我建议永远不要使用this关键字。这是毫无意义。不要使参数具有相同的名称,这既令人困惑又愚蠢。为什么要这么做?另外,不要在使用this时传递实例,这也会造成混乱和愚蠢。
Yusha

Answers:


218

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

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

您可以通过在范围内不使用相同名称的成员变量和局部变量来避免首次使用,例如通过遵循通用的命名约定并使用属性(Pascal大小写)而不是字段(驼峰式大小写)来避免与局部变量(也就是骆驼)冲突案件)。在C#3.0中,可以使用自动实现的属性轻松地将字段转换为属性


49
8.在当前实例上调用扩展方法(this.Foo();将起作用,但Foo()不会起作用)
Marc Gravell

4
同样,将自身转换为另一种类型,例如,将显式实现的方法称为like ((ICollection<T>)this).Add(bla)
nawfal

4
将构造链接到相同类型定义的另一个构造函数。 public ClassName(...) : this(...)
Lasse V. Karlsen 2014年

1
@Anand不会在运行时影响性能。假设没有歧义,无论您是编写示例(例如this.someField = someValue还是),编译器的输出都是相同的someField = someValue。这可能会影响编译器的性能,因为编译器将以不同的方式解析源代码,但是任何差异肯定可以忽略不计。
phoog

7
只有遵守样式约定,即属性不能与参数具有相同的名称,才能通过属性访问字段来避免出现第一个问题 恰好流行的C#样式约定满足了这一要求。但是,并非所有C#都是根据该约定编写的。属性本身没有内在的内在性,使this关键字变得不必要。为此,x一个名为的构造函数参数将隐藏一个名为x的成员,无论该成员是字段,属性还是事件。
phoog

246

我并不是说听起来很,但这没关系。

说真的

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

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

我不会为此烦恼。我只是要确保代码根据您的喜好在美学上尽可能令人满意。如果您问10个程序员如何格式化代码,您将获得大约15种不同的见解。需要重点关注的是代码分解的方式。是抽象的东西吗?我是否为事物选择了有意义的名称?有很多代码重复吗?有什么方法可以简化内容吗?我认为正确解决这些问题将对您的项目,代码,工作和生活产生最大的积极影响。巧合的是,这也可能会使另一个人抱怨最少。如果您的代码可以正常工作,易于阅读且具有充分的理据,那么另一个人就不会仔细研究如何初始化字段。他将使用您的代码,赞叹它的出色之处,


35
this关键字是语义上有意义。请参阅下面的@JasonBunting评论。您将样式的过度this使用与其实际用途混淆了。您的言论不只是轻率,这是错误的!
Dan Barowy 2013年

12
如果有机会,您可能需要重新阅读我的答案。我谈论的是在需要正确语义的情况下使用它。您可能还想看看起源问题。它显示了在语义上不必要的示例中的用法。因此,我不确定我所说的完全是“错误的”。我的回答肯定不是轻率的。
Scott Wisniewski 2013年

9
你知道你的回答对我有什么感觉吗?在这两行之间,我读到“你怎么敢问这样的问题?” -我认为这确实没有建设性。没有人知道一切-这就是我们拥有Stackoverflow的原因:帮助他人并获得帮助。您知道一些话题,有些认识其他话题。互相帮助,不要互相争斗。请考虑一下。
马特

9
我的意思不是嘴,但这是迄今为止最糟糕的答案之一。我不认为将其与您的工作或个人生活进行比较有什么用。仅仅因为有些事情不如其他重要,并不意味着它们不重要。拥有一致的编程风格并非无关紧要(请阅读有关您选择的代码可读性/可维护性的书)。
aioobe

4
我认为您可能误解了我的观点。并不是说“拥有一致的风格”是不好的。我什么都没说。正是“我的风格指南应强制使用'this'这个问题。作为所有字段访问的前缀?” 是任意和反复无常的。
Scott Wisniewski 2015年

96

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

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

54

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


9
但是,如果您忘记使用它,他们会感到困惑
surfen 2011年

2
@surfen可以通过其他样式检查来避免,例如,在Java中,您可以使用Checkstyle并在完整构建后运行它(并且在任何流行的迭代/ OO语言中都将提供类似的工具)
Maarten Bodewes 2014年

5
@surfen好像您在模棱两可的情况下忘记了它。我可以通过说“但是如果您忘记了……”来打破任何争论。
Askolein 2014年

6
大多数人似乎从未阅读,优化或重写别人的代码!预选赛可以节省时间和动力!如果您没有看到任何代码行,则没有限定符的情况就像魔术一样。因此,您只浪费时间检查这些变量的来源。
2014年

3
我知道这是一篇非常古老的文章,但是我不得不对这个答案的讽刺之处发表评论(我恰好同意)。在反对邪恶的匈牙利符号的圣战中,任何敢于为成员变量加上“ m_”前缀的人都被嘲笑,因为区分成员变量只是没有用或不需要。
Michael J.

38

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


我想尽可能地区分类变量,因此代码更加清晰。我以前使用前缀m_(成员变量),例如私有字符串m_name。现在我就用这个,例如,如果我有类Test {private string a; 公共someMethod(){this.a =“ foo”; }
宽带

36

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

如果存在歧义(例如在Corey的示例中)或需要将对象作为参数传递(例如Ryan的示例中),请使用“ this” 。否则没有理由使用它,因为能够基于范围链解析变量应该足够清楚,以至于不需要限定变量。

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

编辑:@Juan:呵呵,我在语句中没有看到任何不一致的地方-当我使用“ this”关键字(在C#文档中有说明)时,有3个实例,而这些都是您真正需要它的时候。在没有阴影的情况下,在构造函数中的变量前面加上“ this”仅是浪费击键,也浪费了我的阅读时间,这没有任何好处。


21
@ JasonBunting:您有时不能做某些事情,而不能做其他事情……这令人困惑…… 希望我永远不要在您的代码中工作您不能总是假设将来阅读您的代码的人会理解您的内容写的,你需要尽可能清晰,并实现它的一个方法是一致
胡安

@juan,十年后。您仍然认为使用“ this”是一种好习惯吗?:)
Scott Adams

2
@ScottAdams我仍然相信一致性和清晰度,是
胡安

仅通过查看确定变量的范围(无论是局部变量还是成员变量)呢?“这个”不是为此目的辩解吗?或者您的意思是说,如果我们编写较小的方法,那么足够容易理解变量的范围了吗?
BornToCode

27

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


1
ReSharper告诉我不要使用它。当我同时使用StyleCop和ReSharper时,有点令人困惑:)但是我倾向于上面的Coreys回答,仅在绝对必要时才使用'this'关键字。
Gunnar

@Gunnar,有一个选项可以禁止删除多余的“ this”。在R#中
Winger Sendon '16

@EmperorAiman-是的,我知道。我的观点是,默认情况下,这两种流行的格式设置工具是默认的,暗示了两种不同的情况,这可能会造成混淆。“成为或不成为...” :)
Gunnar

11

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

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

例:

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

7

我也倾向于在所有地方都使用它,只是为了确保清楚地表明它是我们正在处理的实例成员。


5

我在可能存在歧义的地方(显然)使用它。不仅编译器含糊不清(在这种情况下是必需的),而且对于查看代码的人也含糊不清。


5

此关键字的另一种罕见用法是,当您需要从实现类内部调用显式接口实现时。这是一个人为的例子:

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

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

4

这是我使用的时间:

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

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


4

[C ++]

我同意“必须时使用它”旅的意见。用这种方法不必要地装饰代码不是一个好主意,因为当您忘记这样做时,编译器不会警告您。人们期待这引入了潜在的混乱这个总是在那里,即他们将不得不考虑一下。

那么,您什么时候使用它?我只是看了一些随机代码并找到了这些示例(我没有通过判断这些是好事还是其他事):

  • 将“自己”传递给函数。
  • 将“自己”分配给指针或类似的东西。
  • 投射,即向上/向下投射(安全或其他),消除常量性等。
  • 编译器强制消除歧义。

3

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


3

当在一个接受对相同类型对象的引用的函数中,我想使其完全清楚我要指向的对象,位置时,使用它。

例如

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

一眼看去,AABB right()指的是什么?这this增加了一些澄清剂。


3

在雅库布·斯图尔克(JakubŠturc)的回答中,他关于在构造函数之间传递数据的第5条建议可能需要一些解释。这是在重载构造函数中,并且this是强制使用的一种情况。在以下示例中,我们可以使用默认参数从无参数构造函数中调用参数化构造函数。

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

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


2

我养成了在Visual C ++中自由使用它的习惯,因为这样做会触发我按'>'键的IntelliSense,并且我很懒。(并且容易出现错别字)

但是我继续使用它,因为我很方便地看到我正在调用成员函数而不是全局函数。


1

我倾向于用_来强调字段,因此实际上根本不需要使用它。同样,R#倾向于将它们重构。


1

我几乎只在从相同类型内部引用类型属性时才使用属性。作为另一个用户提及,我也强调局部场使他们无需显着的这个


1

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

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

1

[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

this 在C ++编译器上

如果C ++编译器没有立即找到符号,它将静默查找符号。有时候,在大多数情况下,这是件好事:

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

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

对我来说,那时候是我想在一个方法内访问成员方法或成员变量的时候。我只是不想因为我写printf而不是写一些随机符号printthis->printf不会编译。

关键是,对于C旧版库(§),多年前编写的旧版代码(§§)或在复制/粘贴是过时但仍处于活动状态的语言中可能发生的任何情况,有时会告诉编译器不播放机智是一个好主意。

这就是我使用的原因this

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

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


1

'这个。' 帮助找到具有很多成员的“该”类中的成员(通常是由于深层次的继承链)。

命中CTRL + Space对此无济于事,因为它还包括类型。在哪里-“这个”。仅包括成员。

通常,一旦有了我想要的内容,便将其删除:但这只是我的风格突破。

就风格而言,如果您是一名独行侠,您可以自己决定;如果您在公司工作,请遵守公司政策(查看源代码管理中的内容,看看其他人在做什么)。在使用它来限定成员资格方面,对与错都没有。唯一的错误是不一致-这是样式的黄金法则。离开挑剔的人。花时间思考真正的编码问题-显然是编码-。


1

我会尽可能使用它。我相信它使代码更具可读性,可读性更高的代码意味着更少的错误和更高的可维护性。


1

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

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


0

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


0

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


0

1-常见的Java setter用法:

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

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

notifier.addListener(this);

0

在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在第二轮检查中,替换模板参数之后。


-2

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

不必要的冗长会带来惩罚。您应该争取的代码应尽可能长,而不再是。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.