为什么C#和C++使用_<variableName>编码约定?

9

我看到了太多的C#和C++代码,其中变量命名惯例似乎要求程序员在变量文本之前使用下划线来编写变量名称。例如:

int? _countMoney;

支持该约定的原理是什么?
10个回答

26

在C#中,我通常使用_作为私有字段的前缀,但从不用于局部变量。这样做的原因是当我需要一个私有变量时,只需键入_,Intellisense就会过滤出列表,更容易找到。这样,我也能够区分私有和局部变量,并且我不再需要为类字段键入this.variablename,而是直接用_variablename


在 IntelliSense 出现之前,我就一直这样做来区分成员变量了。这是从 C++ 时代开始的,而 MS 则使用 m_ 来表示成员变量。 - Peter M
2
如果你无法在几秒钟内确定一个变量是否是方法内局部变量,那么难道不能认为你的方法可能过于复杂吗?至于Intellisense筛选功能,编写针对IDE特定功能的代码真的是个好主意吗? - Justin Holzer
@Justin:虽然我同意你的第一个观点,但是对于第二个观点,我不得不问一下它是否真的是一个坏主意呢?如果它不会影响可读性,但偶尔可以帮助可写性,那么为什么不能使用呢? - Dennis Zickefoose
@Davy8:在我看来(虽然价值不大: )),编码规范和命名约定等内容应该是独立于任何工具/框架/IDE开发的。变量命名约定应该同样适用于基本文本编辑器(如记事本)和Visual Studio或Eclipse等高级IDE。我并不否认Darin或其他人使用某种有助于编写更好代码的技术,我只是想说,我不认为Intellisense的论点是使用特定命名约定的有效理由。 - Justin Holzer
2
@Justin 在原则上我同意你的观点,但实际上,除非另有说明,否则使用VS进行C#编程是一个很自然的假设。当某些事情变得可以假定时(以人类的90%+ish的人性化方式而非编程的99.99%的方式),它们开始变得更加合理,就像现在你可以通常问某人“你的电子邮件地址是什么”,而不必先问他们是否拥有电子邮件地址一样。5-10年前你不能这样做,同样对于Java,你不能假定Eclipse,因为其他IDE也有相当强的立足点。对于Python,你不能假定编辑器的任何东西。 - Davy8
显示剩余2条评论

5

这只是一种简单的方法来识别私有成员变量。


5

在c++中不应该使用_作为前缀。以_开头的名称是为编译器保留的。

c++中最常用的前缀是m_(如'member')

对于C#,使用_非常普遍。

在我们的网站上,我们同时使用c++和C#,始终使用m_以保持一致性。


2
不,C++中以_Uppercase开头的名称是保留的。_lowercase则可以使用。 - Detmar
8
@Detmar:实际上,情况比这更加复杂,但你们两人仍然有一定的观点。 - sbi
1
从标准 "每个以下划线开头的名称都保留给实现,用作全局命名空间中的名称"。理论上你可以这么做,但为什么要冒险呢? - pm100
2
@pm100:“在全局命名空间中。” 在其中使用它来表示成员字段是完全安全的,不仅在理论上安全。 在类外部使用它就有些棘手了,但那样做是愚蠢的。 - Dennis Zickefoose
1
现在本地变量的常见方式是使用后缀 _。 - mmmmmm
@Dennis:只要不让下划线后面跟着大写字母,它就是完全安全的。哦,还有……两个连续的下划线也是被禁止的。如果这些规则那么容易,人们就不会在答案中搞砸它们了。 - sbi

5
Microsoft成员命名指南规定,不应在字段中使用前缀。
不要为字段名称使用前缀。例如,不要使用g_或s_来区分静态和非静态字段。
你可以阅读这里的Microsoft命名指南。 当然,这只适用于C#。

1
我个人不喜欢使用前缀的做法。你的IDE应该清楚地告诉你什么是本地变量,什么是成员变量。当然,这取决于个人口味(或项目编码标准),但这个答案得到了我的赞。 - rmeador
这是我不太赞同的少数准则之一。我使用 m_s_ 来区分实例和静态字段。对我来说,这很重要,因为您应该假设静态字段可以被多个线程访问,因此您应该小心防止线程问题。以这种方式使用前缀使得一眼就能看出是否存在任何问题。这个约定是由Jeffery Richter提出的,他碰巧在制定这个准则时发表了意见。他在这个特定点上可能输了 :) - Brian Gideon
1
@rmeador -IDE语法颜色不一定在阅读时使用,也不会复制到其他环境[例如StackOverflow]。前缀在您的视线中,可以复制到所有环境中。 - Andy Thomas
1
确实,我在编写C#代码时尽量遵循微软的指南,但是我的公司使用前缀来表示局部变量(l)、私有成员字段(m)、静态字段(s)和参数(p)。正如你所说,它们就在你的面前,你不能不知道标识符所指代的内容。VS可能会更好地帮助您区分标识符的来源,但遗憾的是,除非您进行鼠标悬停,否则它不会提供太多帮助,特别是在具有许多标识符的大型代码中。 - SoManyGoblins

4

像其他规范一样,它的目的是使代码更易于理解。

我已经看到过这个约定用于私有字段 - 在这种情况下,很容易看出正在使用私有字段。

您可以对匈牙利命名法提出同样的问题。


4
Joel写了一篇有趣的关于匈牙利命名法的辩护文章:http://www.joelonsoftware.com/articles/Wrong.html - Tim Yates
3
关键是使用"应用程序匈牙利"表示法,而不是"系统匈牙利"! - CaffGeek
虽然我个人不喜欢匈牙利命名法,但如果它被用来描述变量的值,我认为它更加可接受。当人们用它来表示变量类型之类的东西时,我认为它被误用了。在乔尔的文章中,他谈到使用“us”前缀来表示“不安全字符串”。我认为,在像C#这样的现代语言中,如果你想使用这样的前缀,如果你将前缀“us”扩展为“unsafe”,代码会更清晰。 - Justin Holzer

1

就像其他人所说的那样,这种命名约定有助于区分成员变量和局部变量。这带来了两个主要优点:

  • 帮助找出对象状态被修改的地方(例如,对于线程安全非常重要)
  • 防止命名冲突。我可以编写如下构造函数:

    SomeObject(int foo, int bar)
    {
      _foo = foo;
      _bar = bar;
    }
    

    这样,我就不必将参数命名为new_foo之类的名称。


2
在C++中,你可以像这样编写构造函数:SomeObject(int foo, int bar) : foo(foo), bar(bar) {},然后"正确"的事情就会发生。 - Oliver Charlesworth
@sbi:同意。不过对于POD(Plain Old Data)类型的数据,我也倾向于这样做(假设你的“POD”的定义允许包含构造函数!) - Oliver Charlesworth
@Justin:为了消除错误的可能性? - Oliver Charlesworth
@Oli:什么错误?如果你使用的是Visual Studio或大多数现代IDE,变量名可以自动完成。 - Justin Holzer
1
在这种情况下,我个人会尝试更好地描述“_foo”和“_bar”,例如currentFoo/currentBar或backingFoo/backingBar。在许多情况下,使用“current”作为前缀可以描述共享的可变内容,“backing”则通常用于可通过属性访问的内容。但这真的取决于公司指南或个人喜好,具体视情况而定。 - Joseph Ferris
显示剩余5条评论

1

我真的不确定这个约定背后的理由是什么。就我个人而言,我不喜欢使用任何类型的变量名前缀来表示变量的作用域,也不特别喜欢在命名中使用下划线。使用 "this" 关键字并采用小写驼峰式命名私有实例/成员变量有什么不好呢?

public void IncrementFoo()
{
    this.foo += 1;
}

只需要多输入5个字符,但它非常明确。如果您已经采用了小驼峰命名法来命名私有实例变量,那么这就立即告诉您正在访问一个私有实例/成员变量,而您不需要使用任何前缀来表示它。


0
有时人们在成员变量中这样做是为了帮助区分它们和局部变量。如果你直接访问下划线变量,也许你应该使用getter/setter来访问。

这个答案有什么问题吗?我认为这个观点完全正确。 - Lazer

0

在我做Java工作时,我注意到Eclipse中的Java开发人员不会使用下划线来命名变量。原因是什么呢?成员变量在IDE中被彩色编码...因此他们觉得没有必要这么做。出于习惯,我发现在VS IDE中通过某些视觉提示定位成员变量很容易...而下划线就是这样一个相当流行的提示方式。在极少数情况下,你需要查看代码的原始形式——文本——这些类型的提示会极大地帮助你。


0

_ 前缀在 VB.NET 中非常重要,因为它不区分大小写。我们使用 C# 和 VB.NET 进行编码,为了所有人的理智,重要的是在两种语言中具有相同的命名约定。


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