正在写"这个"。之前的实例变量和方法的样式是好是坏?
在C ++和Java中,我讨厌的(?)编程习惯之一是始终在调用或者访问成员之前添加" this"。例如:this.process(this.event)
。
我的一些学生对此发表了评论,我想知道我是否在教坏习惯。
我的理由是:
- 使代码更具可读性易于区分字段和局部变量。
- 使区分标准调用和静态调用更加容易(尤其是在Java中)
- 让我记住,此调用(除非目标是最终目标)可能会在其他目标上结束,例如,在子类中的替代版本中。
显然,这对已编译程序几乎没有影响,只是可读性强。因此,我是否使其更具可读性?
注意:由于没有正确答案,因此我将其转换为CW。
解决方案
我认为它的可读性较差,尤其是在突出显示字段与局部变量不同的环境中。我唯一想看到的" this"是何时需要它,例如:
this.fieldName = fieldName
分配字段时。
就是说,如果我们出于某种原因需要某种区分字段的方法,则我更喜欢" this.fieldName"而不是其他约定,例如" m_fieldName"或者" _fieldName"
我认为更具可读性。出于完全相同的原因,我按照方式进行。
从.Net的角度来看,我使用的某些代码分析工具看到了" this",并立即得出结论该方法不是静态的。使用Java可能需要测试,但是如果在Java中执行相同的操作,则可能会缺少一些性能增强功能。
根本不是个坏习惯。我自己没有这样做,但是当我在代码审查中发现有人这样做时,它总是一个加号。这是质量和可读性的标志,它表明作者正在使用专门的思维过程进行编码,而不仅仅是just之以鼻。
这是非常主观的事情。 Microsoft StyleCop有一个要求此的规则。限定词(尽管它是相关的)。有些人使用下划线,有些人使用奇怪的匈牙利符号。我个人对此有资格。即使没有明确要求避免混淆,因为在某些情况下它可以使一个人的代码更具可读性。
我们可能还需要检查以下问题:
我们为成员变量使用哪种前缀?
我认为最重要的是一致性。有合理的论据支持和反对,因此在考虑使用哪种方法时主要取决于口味。
有时我喜欢写这样的类:
class SomeClass{ int x; int y; SomeClass(int x, int y){ this.x = x this.y = y } }
这样可以更轻松地分辨出哪个参数正在设置哪个成员。
我认为我们正在使它更具可读性。它可以让潜在的将来的疑难解答者知道我们要调用的函数在哪里。
其次,并非不可能有一个全局名称完全相同的函数,或者具有某个名称空间的函数,而该名称空间会"使用"冲突。因此,如果发生冲突,原始代码作者将确定他们正在调用哪个函数。
可以肯定的是,如果存在命名空间冲突,则将破坏其他一些干净的编码规则,但是没有人是完美的。因此,我认为任何不妨碍生产力,有可能减少错误(但是减少的可能性)以及可以使将来的问题排查者目标变得更容易的规则都是一个好规则。
我曾经总是使用它...然后,一位同事向我指出,一般来说,我们会努力减少不必要的代码,因此,该规则也不应在这里适用吗?
如果我们要删除,则需要添加它。在成员变量之前,诸如checkstyle之类的静态分析工具对于检测成员变量隐藏字段的情况非常有用。通过消除这种情况,我们可以不必首先使用它。话虽这么说,我更喜欢在构造函数和设置方法的情况下忽略这些警告,而不是不得不为方法参数提出新的名称:)。
关于静态变量,我发现大多数不错的IDE都会突出显示这些变量,以便我们可以区分它们。它还为诸如静态常量之类的东西使用命名约定。静态分析工具可以通过强制执行命名约定来提供帮助。
我发现几乎没有与静态方法混淆的地方,因为方法签名通常足够不同,以至于不需要进行任何进一步的区分。
Python专家一直在这样做,几乎所有人都喜欢它。他们将其拼写为"自己"而不是" this"。可以通过多种方法将显式的"自我"放入其中,但共识是显式的"自我"对于理解类方法必不可少。
我必须在这里加入"包括这个"营地;我并不是一直这样做,但是从维护的角度来看,好处是显而易见的。如果维护者出于某种原因不使用IDE,因此没有特别突出显示成员字段和方法,那么它们将带来很多麻烦。
"可读性"
我发现特别在不使用IDE时使用" this"很有用(小型快速程序)
Whem我的类足够大,可以将一些方法委托给新类,用最简单的文本编辑器非常轻松地用" otherRef"替换" this"。
IE
//Before this.calculateMass(); this.perfornmDengerAction(); this.var = ... this.other = ...
之后的"重构"
// after this.calculateMass(); riskDouble.calculateMass(); riskDouble.setVar(...); this.other = ...
当我使用IDE时,通常不使用它。但是我认为,这不仅使我们使用OO方法,而且使事情更加OO。
class Employee { void someMethod(){ // "this" shows somethings odd here. this.openConnectino() ; // uh? Why an employee has a connection??? // After refactor, time to delegate. this.database.connect(); // mmhh an employee might have a DB.. well.. } ... etc.... }
与往常一样,最重要的是,如果开发团队决定使用或者不使用它,则该决定将得到尊重。
我发现少即是多。代码中越是多余的垃圾,人们维护它的问题就会越多。就是说,保持清晰一致的行为也很重要。
我更喜欢上面描述的本地分配模式,但不适用于本地方法调用。我同意"一致性是最重要的方面"的观点。我发现此内容更具可读性,但我发现一致的编码甚至更具可读性。
public void setFoo(String foo) { this.foo = foo; //member assignment } public doSomething() { doThat(); //member method }
我的一些同事更喜欢:
public void setFoo(String foo) { _foo = foo; }
3个原因(Nomex套装启用)
1)标准化
2)可读性
3)IDE
1)biggie不是Sun Java代码样式的一部分。
(无需使用其他任何Java样式。)
所以不要这样做(在Java中)。
这是Java蓝领的一部分:到处都是一样的。
2)可读性
如果我们要this.this在每个this.other this.word前面;我们真的this.think可以提高this.readability吗?
如果类中的方法或者变量太多,我们就无法知道它是否是成员...重构。
我们只有成员变量,而在Java中没有全局变量或者函数。 (在其他语言中,我们也可以使用指针,数组溢出,未经检查的异常和全局变量;请欣赏。)
如果我们想告诉该方法是否在类的父类中...
切记在声明中使用@Override,并让编译器告诉我们是否未正确重写。如果要调用父方法,则super.xxxx()是Java中的标准样式,否则请忽略它。
3)IDE
任何没有IDE就能理解该语言并在侧边栏上给出轮廓的编写代码的人都可以自己动手做。意识到如果它对语言不敏感,就会陷入1950年代。没有GUI:陷入50年代。
任何体面的IDE或者编辑器都会告诉我们函数/变量的来源。甚至原始的VI(<64kb)也可以使用CTag来实现。使用cr脚的工具是没有任何借口的。好的是免费赠送的!
有充分的技术理由偏爱使用或者避免使用" this",但这两者并不总是等效的。
考虑以下代码:
int f(); template <typename T> struct A { int f(); }; template <typename T> struct B : A<T> { int g() { return f(); return this->f(); } };
现在,在B <T> :: g()中有两个f()调用。一个人会期望它调用A <T> :: f()
,但是只有第二个会。第一个将调用:: f()
。其背后的原因是,由于A <T>
依赖于T
,因此查找通常无法找到它。这是指向B <T>的指针,它也依赖于T,因此,如果使用它,查找将被延迟,直到实例化B <T>之后。
请注意,这种行为可能不会出现在某些未实现两阶段名称查找的编译器(特别是MSVC)上,但这是正确的行为。
在加入现任雇主之前,我从未见过这种风格。第一次看到它时,我以为"这个白痴不知道,Java / OO语言通常不是他的强项",但事实证明,这是一个经常发生的麻烦,并且在一些项目中是强制性的,尽管这些项目也使用
if (0 == someValue) { .... }
有条件的方法,即在测试中将常量放在第一位,这样就不会冒写作的风险
if (someValue = 0)
对于无视其编译器警告的C程序员而言,这是一个常见的问题。事实是,在Java中,上面的代码只是无效的代码,将被编译器丢弃,因此它们实际上使代码的直观性降低,毫无益处。
因此,对我而言,这些事情并没有显示出"作者正在用专门的思维过程进行编码",而是让我感到惊讶的是,这些人只是遵循那些别人曾经告诉过他们而又不问或者不知道的规则的人。首先制定规则的原因(因此不适用规则)。
我所听到的原因主要归结为"最佳实践",通常是引用乔什·布洛赫(Josh Bloch)的"有效Java"(Effective Java)在这里产生巨大影响的原因。但是,实际上,Bloch甚至在我认为他可能必须提高可读性的地方甚至都没有使用它!再一次,这似乎更像是被告知要这样做但不知道为什么的人正在做的事情!
就个人而言,我倾向于与Bruce Eckel在Java思维(第3版和第4版)中所说的更加一致:
"有些人会迷恋于每个方法调用和字段引用的前面,认为这使它"更清晰,更明确"。不要这样我们使用高级语言是有原因的:它们为我们做事。如果在不需要时将其放入,则会使每个阅读代码的人感到困惑和烦恼,因为他们阅读的所有其余代码都不会在各处使用。人们期望仅在必要时才使用它。遵循一致而直接的编码风格可以节省时间和金钱。
脚注,p169,《 Java思维》,第4版
相当。少即是多,人们。
我使用this
至少有两个原因:
谬误的原因
在C ++,C,Java,Cor JavaScript中进行编码时,我喜欢具有一致的代码样式。我一直使用相同的编码风格,主要是受Java启发,但受其他语言启发。
我还希望在一种语言中保持代码内部的一致性。我将typename
用作模板类型参数,而不是class
,并且我从不将两者混为一谈。这意味着我讨厌一次必须添加" this",但是完全避免使用它。
我的代码很冗长。我的方法名称可以很长(也可以不是)。但是它们始终使用全名,而不使用压缩名称(即getNumber()
,而不是getNbr()
)。
从技术角度来看,这些原因还不够好,但是,这仍然是我的编码方式,即使它们没有(很多)好处,也没有(很多)邪恶。实际上,在我从事的代码库中,其他人编写的历史反范式足以使他们质疑我的编码风格。
等到他们学会写"异常"或者"类"的时候,我会再考虑一下所有这些。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
真正原因
尽管我赞赏编译器的工作,但我还是要使联合国产生一些歧义。
例如,我(几乎)从不使用using namespace MyNamespace
。我或者使用完整的名称空间,或者使用三个字母的别名。我不喜欢模棱两可,也不喜欢当编译器突然告诉我"打印"函数相互碰撞时。
这就是为什么我在全局名称空间之前为Win32函数添加前缀的原因,即总是写:: GetLastError()
而不是GetLastError()
。
这和this
一样。当我使用" this"时,我有意识地限制了编译器的自由,如果它找不到真正的符号,则可以搜索其他符号。这意味着方法以及成员变量。
显然,这可以用作反对方法重载的论据。但这只会是显而易见的。如果编写重载方法,则希望编译器在编译时解决歧义。如果a不写this
关键字,那不是因为我要编译器使用另一个符号而不是我想要的符号(例如函数而不是方法,或者诸如此类)。
我的结论呢?
总而言之,这个问题主要是样式问题,并且是由真正的技术原因引起的。我不希望有人不写" this"而死。
至于布鲁斯·埃克尔(Bruce Eckel)在他的" Thinking Java"中的引用……他在他的书中一直对Java / C ++所做的偏颇比较并没有给我真正的印象(奇怪的是,没有与C#的比较),所以他对"这个`,在脚注中完成...好吧。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
可读性较差,除非学生当然仍然像此处的学生一样仍在绿屏终端上...精英人士会提高语法。
我也听说有传闻说他们也有重构工具,这意味着我们不需要" this"。搜索和替换,他们可以通过一次按键删除那些令人讨厌的多余问题。显然,这些工具甚至可以拆分方法,因此它们在大多数情况下都很好,也很短,就像它们本来应该是一开始的那样,然后甚至对于绿色筛选器来说,哪些var是字段也很明显。