C# 中的匈牙利命名法

36

在使用C#之前,C++是我的主要编程语言。而匈牙利命名法深深地印在我的心中。

我在没有阅读C#书籍或其他语言指南的情况下完成了一些小项目。在这些小的C#项目中,我使用了类似于

private string m_strExePath;

直到我在 Stack Overflow 上看到一篇文章说:

不要使用匈牙利命名法。

那么为什么?难道我是唯一一个在我的 C# 代码中使用 m_strExePath 或 m_iNumber 的人吗?

19个回答

53
Joel Spolsky有一篇关于这个话题的好文章。简要概括一下,实际使用中有两种匈牙利命名法。
第一种是“系统匈牙利”,其中使用前缀指定变量类型。例如,“str”表示字符串。这几乎是无用的信息,特别是现代IDE将会告诉您类型。
第二种是“应用程序匈牙利”,其中使用前缀指定变量的目的。最常见的例子是使用“m_”来表示成员变量。如果正确使用,这可以非常有用。
我的建议是尽量避免使用“系统匈牙利”,但在有意义的情况下一定要使用“应用程序匈牙利”。我建议阅读Joel的文章。它有点啰嗦,但比我能更好地解释它。
这篇文章最有趣的部分是,匈牙利命名法的原始发明者Charles Simonyi创建了“应用程序匈牙利”,但他的论文被严重误解,结果产生了可怕的“系统匈牙利”。

我们之前已经讨论过这个问题,我完全理解 "Apps Hungarian" 的观点,但我想指出,在 C++ 中使用 Scott Meyers 在他的书籍 "Effective C++" 中描述的技巧(第 18 条,第 78 页),实际上也不需要这种方式。 - Dave Van den Eynde
3
我有第二版的资料,并且第18条是“努力实现完整而简洁的类接口”,但这与此无关。 - 17 of 26
9
当IDE可以告诉你某个变量是否是成员变量时,我不认为应用匈牙利命名法有什么意义。 - Camilo Martin
1
@CamiloMartin 我个人有时会使用它,所以我的构造函数看起来像这样(带有“something”参数):this._something = something,而不是this.something = something;如果没有一些区分字段和参数的方法,我曾经输入过 something = something,导致该字段被初始化为零,这很难在后来发现。请注意,在某些地方,.NET参考源仍然使用m_MemberVariable作为私有变量,并且MSDN不再指定私有字段的命名约定。 - jrh
1
对于自动属性无法使用的情况,返回 MyProperty 而不是 myProperty 将会导致 StackOverflowException;如果你在打字时按错了 tab 键,智能感知会高兴地自动完成到 MyProperty,但如果你用字段作为前缀,则不那么容易。另见:Jeff Atwood 的文章 - jrh

34
在进行用户界面设计时,我发现保持匈牙利命名法非常有用。像文本框、标签和下拉列表这样的项目往往更容易快速理解,而且通常会出现重复的控件名称:
lblTitle = Label
txtTitle = TextBox
ddlTitle = DropDownList

对我来说,这种写法更易于阅读和解析。否则,由于IDE的进步(特别是Visual Studio),匈牙利命名法无法适用。
此外,Joel on Software有一篇关于匈牙利命名法的优秀文章,标题为:让错误代码看起来像错误,提出了一些支持匈牙利命名法的好论点。

15
我不同意。我认为在这种情况下,情况甚至更糟,特别是当你使用具有较长名称的控件或三个字母缩写与另一个控件的三个字母缩写相冲突时。我们应该使用TitleLabel、TitleTextBox或TitleDropDown等控件名称。 - John
3
@John:我完全同意。我们没有字符限制,应该使变量看起来美观易读。 - Jeff Yates
4
@Jeff & John - 仅仅因为我们没有字符限制并不意味着应该使用它。更小而简洁的变量比更长的表达式变量更好。 - Gavin Miller
4
我仍然不同意。追求简洁而非描述性是没有充分理由的。变量名应尽可能地长。m_lblName和theLabelThatHoldsSomeonesName之间有一个适当的平衡点。 - Jeff Yates
2
我也这样做,而且我认为这是完全有道理的。往往你会从代码后台来处理控件,而这些对象并没有在那里声明,而是在某个标记中声明的。我喜欢从代码后台了解我要处理的东西的类型,而不必查看标记 :) - cwap
显示剩余2条评论

30

虽然不是唯一的人,但我觉得使用匈牙利命名法还是相对较少。个人来说,我不喜欢简单地重复声明中已经存在的类型信息的匈牙利命名法。(“真正”的匈牙利命名法的粉丝会解释其中的区别-它从来没有让我太烦恼,但我可以理解他们的观点。如果你为长度和重量等单位使用常见前缀,即使两者都是整数,也不会意外地将一个长度变量赋值为重量值。)

然而,对于私有成员,你可以随意做你想要的事情-与你的团队达成一致的命名约定即可。重要的是,如果你希望你的 API 与 .NET 的其余部分相适应,则不要在公共成员(包括参数)中使用匈牙利命名法。


@Jon:他们说使用匈牙利命名法不是一个好的做法,但是否会有真正的问题?它会引起任何特定的伤害(如效率/编译器问题等)吗? 就个人而言,我在我的代码中不使用匈牙利命名法,但对于可视化元素,如文本框、标签等,我分别使用txt和lbl。 请发表评论。 - Prerak K
2
不,变量名并不会影响效率或编译时间等方面。它们更多地影响可读性。 (哦,仅通过大小写变化来改变公共成员将限制从诸如VB之类的不区分大小写语言使用该类型的能力。) - Jon Skeet

21

不,你并不是唯一一个这样做的人。只是普遍认为在C#中使用匈牙利命名法并不是最好的命名方式(因为IDE已经解决了很多匈牙利命名法试图解决的问题)。


1
IDE如何处理真正的匈牙利命名法所涉及的任何问题?我不是在谈论.Net类型,在顶部答案中查看Joel的文章。 - Eldritch Conundrum

12
匈牙利命名法是一个极其糟糕的错误,在任何语言中都不应该使用它。在C++中也不应该使用它。给变量起个有意义的名字,这样你就知道它们的用途。不要为了复制IDE可以给出的类型信息而命名它们,这些信息可能会改变(而且通常无关紧要)。如果你知道某个东西是一个计数器,那么它是int16、32还是64并不重要。你知道它是一个计数器,因此任何对计数器有效的操作都应该是有效的。对于X/Y坐标,同样的论据也适用。它们是坐标。它们是浮点数还是双精度浮点数并不重要。知道一个值是以重量、距离或速度单位表示可能是相关的。但它是一个浮点数并不重要。
事实上,匈牙利命名法只是由于误解而产生的。发明者本来想让它用来描述变量的“概念”类型(它是一个坐标、一个索引、一个计数器、一个窗口?)
但是读他描述的人们认为他所说的“类型”是指实际的编程语言类型(int、float、零结尾字符串、char指针)。
这从未是本意,而且这是一个可怕的想法。它复制了IDE可以更好地提供的信息,并且在第一位上并不那么重要,因为它鼓励你在最低可能的抽象级别上编程。
那么为什么?我是唯一一个在我的C#代码中使用m_strExePathm_iNumber的人吗?
不是。不幸的是不是。告诉我,如果exePath不是一个字符串,那么它会是什么?作为你代码的读者,我为什么需要知道它是一个字符串?知道它是可执行文件的路径不就足够了吗?`m_iNumber`只是命名不当。这是什么数字?它是干什么用的?你已经告诉我两次它是一个数字,但我仍然不知道数字的含义。

3
如果我要浪费一秒钟的时间悬停在变量名称上方,IDE可以提供类型信息,但只有这样才能看到它 :-) 我更喜欢一眼就能看到它... 为了对你的例子提供对立观点:exePath 很可能是一个 System.IO.FileInfo 对象,它是一个文件路径的包装器,提供对常见文件系统操作的轻松访问。我真的不认为在变量名前加前缀有什么问题。我发现这使得代码检查和调试更容易。 - Jordan Rieger
4
你为什么需要这个类型呢?当我编程时,我希望知道变量代表什么,而不是它的类型。如果你的exePathFileInfo类型,那它命名不当,那就是你的问题所在。变量的名称表明它是一个路径,而不是一个实际文件。因此,当我使用它时,我希望它的行为像一个路径名,而不是一个文件。 - jalf

10

你肯定不是唯一一个这样的人,但我希望你是下降趋势中的一部分 :)

匈牙利命名法的问题在于它试图通过命名约定实现一种类型系统。这是极其有问题的,因为它是一种仅包含人工验证的类型系统。项目中的每个人都必须同意相同的标准,进行严格的代码审查,并确保所有新类型都被分配了适当和正确的前缀。简而言之,在足够大的代码库中无法保证一致性。如果没有一致性,那么你为什么要这样做呢?

此外,工具不支持匈牙利命名法。这似乎是一个愚蠢的评论,但请考虑重构。在匈牙利命名约定系统中,每次重构都必须伴随着大规模的重命名以确保前缀得以维护。大规模的重命名容易受到各种微妙错误的影响。

与其使用名称来实现类型系统,不如仅依赖于类型系统。它具有自动验证和工具支持。新的IDE使发现变量类型(智能感知、悬停提示等)更加容易,真正消除了对匈牙利命名法的最初需求。


6
匈牙利命名法的一个缺点是,在编写初期,开发人员经常更改变量类型,这需要同时更改变量的名称。

这要看情况。 如果您将“i”用作通用整数值,并且不关心字节大小,则更改类型的问题并不是很大,但如果经常更改类型,则编码可能会出现其他更严重的问题。 对于标准值使用某些类型,并在使用对象值时使用完整对象名称作为前缀,当代码复杂时,代码将更易于阅读。而且,您应该根据代码中较难的部分选择样式指南,而不是简单的部分。 - Per Ghosh

5

如果你使用的是VS IDE而不是文本编辑器,匈牙利命名法很少有价值,它会降低可读性而不是提高可读性。


5
匈牙利命名法在C编程和指针的弱类型本质方面具有真正的价值。基本上,早期跟踪类型的最简单方法是使用匈牙利命名。
在像C#这样的语言中,类型系统会告诉您所需了解的一切,并且IDE以非常用户友好的方式呈现给您,因此根本不需要使用匈牙利命名。
至于不使用它的充分理由,那么有很多。首先,在C#和许多其他语言中,您经常创建自己的类型,那么“MyAccountObject”类型的匈牙利命名将是什么呢?即使您可以决定合理的匈牙利命名,它仍然使实际变量名称稍微难读,因为您必须跳过开头的“LPZCSTR”(或任何其他内容)。更重要的是维护成本,如果您从列表开始并转换为另一种类型的集合(这是我目前似乎经常做的事情之一),那么您需要重命名所有使用该类型的变量,而这并没有真正的益处。如果您一开始只使用一个好的名称,那么您就不必担心这个问题。
在您的示例中,如果您创建或使用一些更有意义的路径类型(例如Path),则需要将m_strExePath更改为m_pathExePath,这很麻烦,在这种情况下实际上并没有什么帮助。

3

我目前只看到两个领域在使用匈牙利命名法:

  • 类成员变量,以下划线开头(例如_someVar
  • WinForms和WebForms控件名称(btn表示Button,lbl表示Label等)

成员变量前面的下划线似乎会在未来一段时间内继续存在,但我预计匈牙利命名法在控件名称上的流行度将会减弱。


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