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

在构造函数中:

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# 中的关键字。

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

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

其他提示

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

严重地。

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

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

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

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

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

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

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

我不敢相信所有的人都说始终使用它是“最佳实践”等等。

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

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

编辑:@胡安:呵呵,我在我的陈述中没有看到任何不一致之处 - 有 3 个实例我会使用“this”关键字(如 C# 文档中所述),而这些时候您实际上 需要 它。当没有发生阴影时,将“this”放在构造函数中的变量前面只是浪费击键,浪费我阅读它的时间,它没有任何好处。

我什么时候都用它 风格警察 告诉我。 风格警察 必须遵守。哦是的。

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

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

例子:

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

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

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

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

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

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

这是我使用它时的情况:

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

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

[C++]

我同意“必要时使用它”的观点。不必要地装饰代码 这不是一个好主意,因为当您忘记这样做时,编译器不会警告您。这给期待的人带来了潜在的困惑 永远在那里,即他们必须 思考 关于它。

那么,你什么时候会使用它呢?我刚刚浏览了一些随机代码并找到了这些示例(我不会判断这些是否是 好的 要做的事情或其他):

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

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

例如

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 添加了一些澄清。

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

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

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

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

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

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

我倾向于用 _ 下划线字段,所以实际上不需要使用它。R# 也倾向于将它们重构掉......

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

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

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

this 在 C++ 编译器上

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

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

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

为我, ,这些时候是在方法内我想要访问成员方法或成员变量的时候。我只是不想仅仅因为我写了一些随机符号 printf 代替 print. this->printf 不会编译。

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

这些是我使用的原因 this.

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

(§§)意识到“你需要包含一个标头,但是包含这个标头会破坏你的代码,因为它使用了一些带有通用名称的愚蠢宏”是其中之一 俄罗斯轮盘赌 程序员一生的精彩瞬间

'这。'帮助与许多成员一起在“这个”课上找到成员(通常是由于深层继承链)。

按 CTRL+Space 对此没有帮助,因为它还包含类型;就是在哪里。仅包括成员。

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

就风格而言,如果你是独行侠——你自己决定;如果您在公司工作,请遵守公司政策(查看源代码管理中的内容并看看其他人在做什么)。就用它来确定会员资格而言,没有对错之分。唯一的错误是不一致——这是风格的黄金法则。留下那些吹毛求疵的人吧。相反,花时间思考真正的编码问题——显然是编码。

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

我用它来调用 智能感知 就像 约翰·麦格, ,但完成后我会返回并删除“this->”。我遵循 Microsoft 约定,在成员变量前添加“m_”前缀,因此将其保留为文档将是多余的。

1 - 常见的 Java setter 习惯用法:

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

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

notifier.addListener(this);

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

当许多开发人员在同一个代码库上工作时,您需要一些代码指南/规则。在我工作的地方,我们决定在字段、属性和事件上使用“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 在模板参数替换后,在第二轮检查。

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

不必要的冗长会带来惩罚。您应该争取代码的长度恰好满足其需要的长度,而不是更长。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top