你使用什么前缀来命名成员变量?

34
毫无疑问,为了能够轻松区分“普通”变量,给成员变量加前缀是理解代码的重要一环。
但你使用哪种前缀呢?
在我参与的项目中,有的使用m_作为前缀,有的只使用下划线(个人不太喜欢,因为仅使用下划线并不能明确展示该变量是成员变量)。
另一个项目中,我们使用了长的前缀形式,其中还包括了变量类型。例如,mul_unsigned long 类型的member 变量的前缀。
现在告诉我你使用的是哪种前缀(请说明原因)。
编辑:大多数人似乎在编写代码时没有使用特殊前缀来表示成员变量!这取决于语言吗?根据我的经验,C++ 代码往往会使用下划线或 m_ 作为成员变量的前缀。其他语言呢?

我们真的需要为这个问题加上两个新标签吗?“member”和“prefix”?我认为“编码风格”和“编码标准”已经足够了。 - Aardvark
33个回答

56
毫无疑问,在理解代码时,给成员变量加上前缀是必要的,这样它们可以轻松地与“普通”变量区分开来。
我对这种说法持有异议。如果您有半好的语法高亮显示功能,这完全没有必要。一个好的IDE可以让你用可读的英语编写代码,并以其他方式显示符号的类型和范围。Eclipse通过突出显示符号的声明和用途来执行得很好。
编辑,感谢slim:像Eclipse这样的良好语法高亮显示器还可以让您使用粗体或斜体文本,或者完全更改字体。例如,我喜欢用斜体表示静态内容。
另一个编辑:从这个角度考虑;变量的类型和范围是次要信息。它应该是可用和易于找到的,但不应该向您大喊大叫。如果您使用类似于m_或LPCSTR的前缀,那么这就成为了噪音,而您只想阅读主要信息——代码的意图。
第三次编辑:这适用于任何语言。

6
好的,但有时我们在代码审查时会使用打印出来的文件。如果没有彩色打印机,你就无法进行语法高亮... - Thomas Koschel
7
那么,如果你在1%的代码审查时间里没有彩色打印机,你就不得不用难以阅读的代码度过其余的99%时间?和你的老板谈一谈买个打印机吧。 - easeout
8
对于设计成在IDE中解析的语言,如Java或C#,这是适用的,但对于C++和C则不然(其中某些结构体成员具有特定于该结构体的唯一前缀)。这是非常特定于语言的,就像大多数语法一样。 - Roger Pate
13
对于C#来说,这根本不适用。基本上,你们大多数人都陷入了一种逻辑谬误:认为“因为对你来说不是问题,就不会是任何人的问题”。对于C#,请使用“m_”或“_”,不要自我中心。并不是每个人都像你一样。基本上,共享语法是用于审查的工具,其目标不是针对独立开发者 - 它的目标是提供一个统一的“语言”,使其他人可以理解,而不受你个人怪癖和习惯的影响。 - Casper Leon Nielsen
4
我还没有听到一个令人信服的反对使用简单的“m”和“s”前缀的论点。有了前缀,我不必考虑无论我的当前上下文是什么,是否需要使用“this”。这也是显而易见的,不像语法高亮。颜色和字体样式的含义在不同的开发环境中可能会有很大的差异。如果我在你旁边工作,我不想学习你的含义。不好意思,但这个回答的论点很弱。我永远不想在一个开发者认为“变量类型和范围”是次要信息的项目上工作。 - James Wald
显示剩余7条评论

46
我不使用任何前缀。如果我遇到将局部变量或方法参数与类成员混淆的危险,那么无论是方法还是类都过长,并且受益于分解。这(可以说)不仅使代码更易读,而且有点“流畅”,更重要的是鼓励良好结构的类和方法。最终,问题归结为与前缀或无前缀无关。
更新:嗯,口味和偏好会改变,不是吗..我现在使用下划线作为成员变量的前缀,因为它在识别局部变量和成员变量方面证明了其有利作用。特别是新团队成员有时很难区分两者。

9
能否给我投反对票的人请澄清一下?问题是“你使用什么”,而不是“什么是最好的和唯一的方法”。即使是“什么是最好的和唯一的方法”,每个人对于什么对他个人最有效都可能有非常不同的观点,不是吗? - petr k.
2
当您将变量传递到函数中时,这很有用。 Function(int value) { m_value = value; } 否则,您必须为'value'考虑两个不同的名称。 - Martin Beckett
1
@mgb - 你也可以这样写:Function(int value) { this.value = value; } - Rob Sobers
4
除了一个方面,我完全同意你的观点:使用前缀有助于强调改变私有变量将使这些更改对其他方法调用持续存在。这种强调可以帮助丢三落四的开发人员避免创建新的错误。 - Phil
4
+1 表示更新确认了您最初的看法是基于个人偏见,现在由于经验而“知道得更好”。 - Casper Leon Nielsen
显示剩余5条评论

42

没有。我曾经使用下划线,但在一个项目中被其他人劝阻,也没有想念它。一个好的IDE或者良好的记忆可以告诉你什么是成员变量,什么不是。我们项目中有一个开发人员坚持在每个成员变量前加上“this.”,当我们处理名义上属于他的代码区域时,我们会迎合他。


3
如果不使用下划线或m_,当成员变量名称与成员函数参数名称发生冲突时,就会出现问题。 - 17 of 26
5
使用更好的名称来解决名称冲突... ;-) - Shog9
1
如果你保持方法足够短,以至于可以在单个屏幕内(正如我所看到的建议),那么一眼查看方法声明就足以澄清变量来自何处。 - Adrian Clark
29
你真的想依赖某个特定集成开发环境的功能来使你的代码更易读吗? - richq
1
保罗,我是在回应斯科特的话,他说“如果IDE支持将成员变量与其他变量区分开来进行着色,那就太好了”。我一直是一个坚定的m_-er,但现在我对此有些怀疑,因为我在这里看到了一些评论。 - richq
显示剩余14条评论

22

仅使用下划线。

在我的情况下,我之所以使用它,是因为我的工作场所的编码标准文件中这样规定。然而,我无法理解在变量名称开头添加m_或某些可怕的匈牙利命名法的意义。极简风格的“仅使用下划线”使其更易读。


这是我的个人偏好,尽管如果字段是静态的,我喜欢使用 s_。 - Craig Tullis

20

保持一致性比任何事情都更重要,因此选择您和您的团队成员都可以同意并坚持不懈的东西。如果您编码所使用的语言有约定,请尝试遵守它。没有什么比遵循前缀规则不一致的代码库更令人困惑的了。

对于c ++而言,除了_有时会给编译器关键字加前缀的事实之外,还有一个理由可以优先选择m_,即m代表成员变量。这也为您提供了将局部变量与其他类型的变量(s_表示静态变量,g_表示全局变量,但千万不要使用全局变量)区分开来的能力。

至于那些说IDE总是会照顾你的评论,IDE真的是你查看代码的唯一方式吗?您的差异工具是否具有与IDE相同水平的语法突出显示质量?您的源代码版本控制工具呢?您甚至从未在命令行中查看过源文件吗?现代IDE是非常高效的工具,但不管在哪种情境下阅读代码,代码都应该易于阅读。


使用下划线后缀可以解决C++下划线前缀问题。需要一点时间来适应,但现在我几乎更喜欢这种方式。 - User
关于差异工具的优点非常好,这是除了使用打印版进行代码审查的问题之外的另一个方面。我只看到反对使用基于个人审美偏好的前缀的论点,并且恕我直言,谁在乎微软的编码指南文档说什么?我见过很多带有前缀的微软代码示例,我没有看到任何从中排除它们所得到的功能好处。 - Craig Tullis

12
我更喜欢使用this关键字。这意味着使用this.datathis->data而不是某些依赖于社区的命名。
因为:
  • 在现今的IDE中,输入this.会弹出智能提示
  • 对于每个人来说都很明显,而不需要知道定义的命名
顺便说一句,在好的IDE中,用字母前缀表示变量类型已经过时了,并且让我想起了Joel的文章

1
这不是一个好的做法,因为很容易忘记这个 ;) - compie
3
很容易忘记做很多事情——这并不意味着这是一个不好的习惯。 - Radu

8
我们使用m_和稍作修改的Simonyi记法,就像Rob在之前的回答中所说的那样。因此,前缀似乎很有用,而m_不会太过于突兀,并且易于搜索。
为什么需要记法?为什么不遵循(对于.NET)依赖名称大小写的Microsoft命名建议呢?
先回答后一个问题:如上所述,VB.NET对大小写不敏感。数据库和(尤其是)DBA也是如此。当我必须区分customerID和CustomerID(例如在C#中)时,我的大脑会疼痛。因此,大小写是一种记法,但不是一种非常有效的记法。
前缀记法具有以下几个优点:
1. 在不使用IDE的情况下增加了对代码的人类理解力。如在代码审查中-最初我仍然发现在纸上进行审查最容易。 2. 你是否曾经编写过T-SQL或其他RDBMS存储过程?在数据库列名上使用前缀记法真的很有帮助,特别是对于那些喜欢使用文本编辑器进行此类操作的人来说。 3. 或许简言之,前缀作为一种记法形式很有用,因为仍然存在着没有智能IDE的开发环境。将IDE(软件工具)视为允许我们使用一些快捷方式(如智能感知输入)的工具,但并不构成整个开发环境。
IDE是集成开发环境,就像汽车是交通网络一样:只是更大系统的一部分。当有时走过空地比沿着标记路线走更快时,我不想遵循“汽车”约定。依靠IDE跟踪变量类型就像需要汽车的GPS穿过空地一样。最好将知识(尽管可能会有点笨拙,例如“m_intCustomerID”)以可移植的形式保存下来,而不是在每次微小的改变方向时都返回汽车。
话虽如此,m_约定或“this”约定都是可读的。我们喜欢m_,因为它易于搜索,同时还允许变量类型跟随它。同意一个简单的下划线被太多其他框架代码活动使用。

只有一些数据库是不区分大小写的,实际上即使是微软SQL Server也可以配置为对对象名称区分大小写。话虽如此,出于纯粹功能的原因,我更喜欢前缀,所以我很高兴你是支持者,并且我认为基于美学或基于IDE使成员变量显而易见的推理是非常薄弱的推理。 - Craig Tullis
1
你上一段似乎表明你认为 this. 符号不容易搜索,并且它不允许变量类型跟随?虽然 m_intCustomerID 让我感到不舒服。 - bornfromanegg
请使用 m_iCustomerID 替代 m_intCustomerID。匈牙利命名法的重要之处在于能够快速阅读代码并理解其含义。匈牙利命名法应该根据所用项目进行调整。原因是您应该尽量减少缩写的数量。 今天,所有 int 类型都可以用 i 进行缩写。 在 80 年代,有 NEAR、FAR 和 HUGE 指针。它们需要适应当时的情况和其他相关问题。 如今,对于基本类型,您只需要 i、u、d、it(迭代器)、b 等,然后您就拥有了它们全部。 - Per Ghosh

6
使用C#,我已经从'm_'前缀转移到了仅使用下划线,因为'm_'是来自C++的遗产。
官方的Microsoft指南告诉你不要使用任何前缀,在私有成员上使用驼峰式大小写,在公共成员上使用帕斯卡式大小写。问题在于,这与同一来源的另一个指南相冲突,该指南规定您应该使所有代码与.NET中使用的所有语言兼容。例如,VB.NET不会区分大小写。
所以对我来说只需要使用下划线。这也使得通过IntelliSense轻松访问,而且只调用公共成员的外部代码不必看到视觉上混乱的下划线。
更新:我认为C#“this.”前缀并没有帮助到VB中的“Me.”,后者仍然会将“Me.age”视为“Me.Age”。

1
同意,但是FYI: MS Framework设计准则3.6.4 命名字段 "字段命名准则仅适用于静态公共和受保护的字段。内部和私有字段不在准则范围内,而公共或受保护的字段则不允许根据..." - Robert Paulson
我正在使用《框架指南》作为参考,所以它可能会落后一些。或者是我记错了。你能链接到你的声明吗?从我记得的来看,它说“私有字段不包括在内...但建议…”之类的话。 - Seb Nilsson
这两个语句有什么冲突吗?私有成员在其他语言的其他类中既不可访问也不被使用。 - oɔɯǝɹ
任何公共成员字段的存在都应视为问题。 - Craig Tullis
Microsoft Guidelines是针对那些在编写解决方案时遇到问题的开发人员。C#的整个理念是,开发人员应该避免编写自己的解决方案,而应该使用来自.NET和其他库的代码。 这对于微软来说最有利可图,也对于经常需要更换开发人员的公司来说是有益的。 - Per Ghosh

5

这取决于我使用的框架!如果我在编写MFC代码,则使用m_和匈牙利标记。对于其他东西(通常是STL / Boost),我会为所有成员变量添加下划线后缀,而不必使用匈牙利标记。

MFC类

class CFoo  
{  
private:  
    int m_nAge;  
    CString m_strAddress;  
public:  
    int GetAge() const { return m_nAge; }  
    void SetAge(int n) { m_nAge = n; }  
    CString GetAddress() const { return m_strAddress;  
    void SetAddress(LPCTSTR lpsz) { m_strAddress = lpsz; }  
};

STL类

class foo  
{  
private:  
    int age_;  
    std::string address_;  
public:  
    int age() const { return age_; }  
    void age(int a) { age_ = a; }  
    std::string address() const { return address_; }  
    void address(const std::string& str) { address_ = str; }  
};

现在这可能看起来有点奇怪 - 两种不同的样式 - 但对我而言有效,编写许多不使用与MFC本身相同样式的MFC代码只会显得很丑。

在MFC中,为与控件内容相关联的变量使用m_,为控件本身使用c_是很有用的。否则,您必须为同一项想出两个不同的名称。 - Martin Beckett

4

我用“m”作为成员变量前缀,用“p”作为函数参数前缀。因此代码将如下所示:

class SomeClass {
    private int mCount;
    ...
    private void SomeFunction(string pVarName) {...}
}

我发现这个方法可以快速告诉你任何变量的基本范围——如果没有前缀,那么它是局部变量。此外,当阅读一个函数时,您不需要考虑传递了什么和什么只是局部变量。


6
我也使用 m。但似乎 p 是不必要的。你真的会丢失参数吗?这意味着你的方法太冗长了。 - Kugel
1
如果没有前缀,那么它就是一个本地变量。然而,准备好让你的思维被震撼 - 参数也是完全相同的本地变量,只是以不同的方式初始化,那么为什么要加前缀呢?如果你把参数和_其他_本地变量搞混了,那么你可能需要更整洁地编写代码。 - underscore_d

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接