使用仅使用大小写与类型名称不同的参数名称是否被认为是C#中的不良做法?


43

对于与类的属性匹配的参数名称,我看到与此类似的问题,但是除了使用C#中的大小写外,对于使用与参数类型名称相同的参数名称,我找不到任何东西。我发现这似乎不是违规行为,但是否认为这是不正确的做法?例如,我有以下方法

public Range PadRange(Range range) {}

此方法采用一个范围,并返回已应用填充的新范围。因此,鉴于通用上下文,我无法想到该参数的更具描述性的名称。但是,我想起了我在阅读《代码完整》中有关“心理距离”的一些提示。它说

心理距离可以定义为区分两个项目的难易程度...调试时,请准备好应对类似变量名之间以及相似例程名之间的心理距离不足所引起的问题。在构造代码时,请选择差异较大的名称,以便可以避免此问题。

我的方法签名有很多“范围”,因此,就心理距离而言,这可能是一个问题。现在,我看到许多开发人员都在执行以下操作

public Range PadRange(Range myRange) {}

我个人对此公约非常反对。向变量名添加“ my”前缀不会提供任何其他上下文。

我也看到以下

public Range PadRange(Range rangeToPad) {}

我喜欢此前缀,而不是“ my”前缀,但总体上还是不在乎。它对我来说太冗长,将其作为变量名尴尬地读取。在我看来,由于方法名称,将填充范围。

因此,考虑到所有这些因素,我的直觉是带着第一个签名。对我来说,这很干净。不需要时不需要强制使用上下文。但是,我是否对自己或将来的开发人员不利于此约定?我违反最佳做法了吗?


35
如果您无法提供更具描述性的参数,那就Range range好了。
罗伯特·哈维

21
在这种情况下,IDE将为“ Range”和“ range”使用不同的颜色,因此很容易看到一个是类型,一个是变量名。
18年

10
是的,我记得。这是在他们的设计准则中考虑的。“考虑为属性赋予与类型相同的名称。” docs.microsoft.com/en-us/dotnet/standard/design-guidelines/...
杰森·泰勒

11
也可以:(Range r至少对于短方法体而言)和Range toPad
Bergi '18

19
我一直认为“我的”前缀是在示例代码中完成的操作,在此示例中,该前缀用于向读者指示应根据上下文将名称更改为其他名称。它实际上不应以任何实际代码结束。
kapex '18

Answers:


100

别想太多,Range range很好。我在C#中使用这种命名已经超过15年,在C ++中使用的命名可能更长,并且从未经历过任何真正的弊端,恰恰相反。

当然,当您在同一范围内(所有相同类型)具有不同的局部变量时,可能需要投入一些精力来正确区分它们。


6
我要添加的另一个例外是当实例对其执行特定操作时。例如,为什么需要该参数还有一些描述性的余地。Wack(Bozo bozoToBeWacked)更重要的是,如果参数是可选的,并且描述该方案中的对象意味着什么/将影响什么。我的经验法则是,如果不看代码而不是显而易见的话,那么它需要一个更好的名称和/或注释。
迈克

17
我将以Wack(Bozo bozoToBeWacked)变量名的冗余为例,该冗余由方法本身充分表达(因此对于原始问题而言是不希望的)。 Wack(Person bozo)然而,它在语义上更有价值,因为它意味着只希望撞死bozo。
Miral

2
在第二段中提到的情况下,我通常会将参数重命名为initialRange。它仍然非常通用,但讨厌程度却几乎不如myRange
Jaquez

@Miral:在诸如这样的情况下,它变得更加相关Punch(Bozo punchingBozo, Bozo bozoToBePunched)。当您必须区分多个事物(在语义上用几乎相同的词来描述)时,详细的命名更有意义。OP的建议Range rangeToPad在他的一个参数方法示例中不是必需的,但是对于包含多个Range对象的方法可能是不可思议的 。
平坦

7
@Flater Punch(Bozo source, Bozo target)会完成工作
Thomas Ayoub

17

我一直在这样做,这让我很放心。如果它是传递给构造函数的参数,并且需要分配给成员,则我的成员也将被命名为range,并且分配将是

this.range = range;

我通常会有一个名为Range的属性。

它们都是相同的东西,只是上下文不同,因此保持一个名称是有意义的,您将只需要记住一个名称。是一回事,区别纯粹是技术上的。

您应该严格限制具有“ this”资格的成员。虽然,但这就是StyleCop的目的。

StyleCop旁注

有争议的保证!

对于那些反对使用“ this。”的人:我见过_,m,m_,什么也没有。语言本身为我们提供了一种非常清晰,明确,普遍公认的方式来表明我们正在与班级成员打交道。到底为什么您要以自己的方式来破坏已经完美的名称?

我能想到的唯一原因是,它是C时代的一种传统习惯,因为没有其他方法可以做到这一点,实际上使它有意义。

“这是更多的角色!” 认真吗 “编译时间会飞涨!” 认真吗 “输入时,我将不得不抬起小指!”。好像打字时间在整个开发时间中具有重要意义。

我认识到,任何与您习惯的风格不同的风格都会引起反对。但是,很难始终如一地使用它。这是它的工作方式:在推送新代码文件之前,我运行StyleCop,它将发现许多缺少“此”限定符的成员。我把“这个”。在剪贴板上,由成员运行并插入。一点都不努力。

StyleCop的功能远不止于此(哈哈)。开发人员可以通过多种方式(仅考虑代码格式)破坏其后继者的维护工作。StyleCop可以防止大多数情况。这是无价的。

如果您是新手,它通常会让您抱怨一两个星期,然后您会喜欢它。


19
对于具有“ this。”的完全合格成员,您应严格要求, “ -1。this除非必要,否则请勿使用。否则就是噪音。使用_range的领域,this是从来不需要除了在扩展方法。
David Arno

12
我同意@DavidArno。“这”只是纯粹的声音。“范围”是一个属性,“ _ range”是一个字段,而“ range”是一个参数。
18年

8
@David如果变量是类成员,则必不可少,它会打乱任何任意前缀,以表示您正在查看类成员,而不是参数或局部变量。
马丁·马特

6
我的IDE将在第二次向自己分配变量的同时射击火球。
Koekje

21
@DavidArno Care解释了为什么“噪声” _优于噪声this.?我认为其中一种具有由语言强制执行的含义(通常具有语法突出显示),而另一种则没有。
克林特

9

我对命名方法,参数和变量的自我指导非常简单:

  1. 如果名称包含正在传递或返回的类型,则说明您做错了。
  2. 用事物的意图而不是事物来命名事物。
  3. 永远记住,代码被读多于编写。

因此,我认为最佳方法签名将是:

Range Pad(Range toPad)

缩短方法名称是不言自明的。

参数名称toPad立即告诉读者该参数可能会通过填充然后返​​回而在原位进行修改。相反,无法假设名为的变量range

此外,在该方法的实际身体,任何其他Range所导入的变量会(应该)通过他们的意图命名的,所以你可能paddedunpadded...... toPad符合这些命名约定,但range只是伸出并没有凝胶。


3
padded/ unpadded对于局部不可变变量听起来不错。但是,如果有一个可变的toPad参数,则在完成填充之后,该名称将toPad不再适合(除非立即返回结果)。Range range在这些情况下,我宁愿坚持。
kapex

@Kapep我就这样称呼它result。它被修改返回。从名称中可以明显看出后者,而从名称中可以看出,因为返回未修改的参数没有任何意义。
maaartinus 18'Apr

Pad方法从签名返回一个Range。对我而言,这意味着我传递的内容将被保留,而不是就地修改,而Range将返回一个新的填充页面。。
亚伦·埃希巴赫

1
我不确定如何看待您的建议。Pad(toPad)感觉有点恕我直言。但是,您可以很好地捍卫自己的观点。您得到我的+0!:)
Eric Duminil

在问题中,它指出“返回一个已应用填充的新范围”。对于您认为的情况,我同意您的
理查德·威利斯

3

对于代码元素(类型,变量,函数等)的命名,要问自己的关键问题是

如果我输入错误,编译器会为我找到吗?

最糟糕的基于错字的错误是一种代码在其中编译和运行的错误,但由于细微的原因,它给出的行为与您期望的不同。而且由于是由于输入错误,通常在检查代码时很难看到。如果输入错误将停止代码的编译,则编译器将标记出导致问题的行,您可以轻松地找到并修复它。

对于类型和变量仅大写不同的情况,情况总是如此。(或者几乎总是-付出足够的努力,我相信您可以使它工作,但是您必须真正尝试一下。)因此,我认为您还可以。

您需要关注的是当前范围内是否存在两个变量,即方法,函数或属性,称为rangeRange。在这种情况下,编译器可能让它通过,并且您将在运行时遇到意外行为。请注意,这是所有这些类型的代码元素中的两个,而不仅仅是“两个变量”或“两个函数”-所有这些元素都可以隐式地彼此转换,从而在运行时产生残酷的后果。您可能会收到警告,但不能保证其他任何事情。如果您有两个声明为的类型称为range和,则会遇到类似的问题Range

还要注意,匈牙利的书写方式也是如此,其中名称以一个或多个字符为前缀,以表达更多含义。例如,如果您有一个名为的变量Range和一个名为的指针PRange,则很容易意外错过P。C#应该抓住这一点,但是C和C ++最多只会给您警告。或更令人担忧的是,假设您有一个称为的双DRange精度版本,并且将其降采样为一个名为的浮动版本FRange。使用偶然的浮动一个(这是容易的,因为键是键盘上的相邻)和你的代码的一种工作,但是当进程中运行的分辨率和下溢出它会在诡异莫测的方式翻倒。

我们已经不再有8个字符,16个字符或任何任意限制的命名限制了。我有时听到新手抱怨较长的变量名使编码花费更长的时间。不过,只有新手对此有所抱怨。认真的编码人员知道,真正需要时间的是找出模糊的错误-命名的错误选择是使自己陷入特定漏洞的经典方法。


只是给读者的注释-对于C#,人们应该真正避免使用匈牙利表示法。虽然它在较早的时候不是语法高亮或受限制的语法很有用,但如今它确实无济于事。
T. Sar-恢复莫妮卡

@ T.Sar甚至在白天,我也充满激情地讨厌它!如您所说,更好的IDE可以解决其目标问题,但它仍然经常出现。例如,由于历史原因,如果您需要与Windows API对话,您仍然会看到它。我不想完全抨击人们喜欢的样式,但是我确实想将它用作显示大写/小写并不是唯一加重命名方式的钩子。
格雷厄姆

我知道您没有提议使用匈牙利表示法,但我也知道年轻开发者在使用好名字的事物方面存在巨大的缺点。可以说“我的代码是以这种超级秘密的忍者编码风格编写的-匈牙利符号!” 听起来对年轻的人来说是不可抗拒的酷。我已经看到太多开发者被酷词的炒作...匈牙利表示法是痛苦,以源代码xX的形式提供
T. Sar-Reinstate Monica

@ T.Sar确实如此。“那些不记得过去的人注定要重蹈覆辙”等等。:/
Graham

1
我们是在谈论原始的匈牙利符号,还是被微软严重误解(在“ Windows团队的文档编写者不经意间发明了后来的系统匈牙利语”附近,以及在Leo Laporte的Joel Spolsky的专栏采访中) 277,2016-12-12,04分钟00秒-06分钟35秒)?
彼得·莫滕森

1

我想补充一则轶事,尽管Range range这在语法上是合法的,但它可能使调试或重构变得更具挑战性。在包含很多Range类型变量的文件中寻找那个名为“ range”的变量?由于这个命名选择,您可能最终会做更多的工作。

但是,这在很大程度上取决于上下文。如果它是一个30行的文件,那么我的陈述实际上并没有发挥作用。


7
对于Windows开发,大多数人使用区分类型和参数或变量的工具。您所描述的内容使我想起了Unix上良好的grep时代。
Frank Hileman '18 -4-20

1
@FrankHileman可能会让您感到惊讶,但是Unix仍然存在,并且grep仍在使用(:D)。由于grep默认情况下区分大小写,因此上述问题根本不存在。但是,即使我们是终端痴迷的Windows使用者,也很少使用grep作为源代码,因为IDE在常规搜索中要好得多。
maaartinus

我认为我们同意平台不是重点。grep是一个很棒的工具,但不是重构工具。在我使用的每个开发平台上都存在重构工具。(OS X,Ubuntu,Windows)。
埃里克·威尔逊

@EricWilson曾经,grep和sed是unix上唯一的重构工具。
Frank Hileman '18

@FrankHileman仅仅因为某种东西被用作重构工具并不意味着它就是一个。我可以在记事本中进行重构,但这不仅仅限于文本编辑器。
埃里克·威尔逊

1

我认为您可以使用Range range当今的一个原因:语法突出显示。现代IDE通常以不同的颜色突出显示类型名称和参数名称。另外,类型和变量具有相当大的“逻辑距离”,不容易混淆。

如果不是这种情况,我会考虑使用其他名称或尝试启用可以突出显示此语法的插件/扩展。


0

当一个函数是通用的时,就可以推断出参数将是通用的,因此应该具有通用名称。

不是您在说什么,而是我看到了执行通用函数的函数,这些函数的参数名称具有误导性。喜欢

public String removeNonDigits(String phoneNumber)

函数名称听起来很通用,像这样,可以在许多情况下应用于许多字符串。但是参数名称奇怪地是特定的,这让我想知道函数名称是否会误导用户,或者……是什么?

因此,可以肯定地说,您可以说Range RangeToPad,而不是说Range range。但是,这会增加什么信息?当然,这是需要填补的范围。还有什么呢?

添加任意的前缀“ my”或“ m_”或其他任何内容,将零附加信息传达给阅读器。当我使用了编译器不允许变量名与类型名相同的语言时(无论是否区分大小写),有时我都使用前缀或后缀,只是为了使其能够编译。但这仅仅是为了满足编译器的需求。有人可能会争辩说,即使编译器可以区分,这也使人类读者更容易区分。但是哇,在Java中,我写了“ Customer customer = new Customer();”这样的语句。十亿次,我从未感到困惑。(我总是发现它有点多余,我更喜欢在VB中,您可以说“将客户作为新客户”,而不必两次给出类名。)

我强烈反对通用名称的地方是在同一函数中有两个或多个相同类型的实例。特别是参数。喜欢:

public Range pad(Range range1, Range range2)

range1和range2有什么区别?我应该怎么知道?如果它们确实是两个通用且可互换的值,那么像

public boolean overlap(Range range1, Range range2)

我希望如果范围重叠,则返回true;如果不重叠,则返回false,因此它们是通用且可互换的。

但是,如果它们不同,请给我一个提示,告诉他们它们如何不同!我最近在开发一个程序,该程序具有“ Place”类来保存有关地理位置的数据,并且该类的变量名为“ p”,“ place”,“ place2”,“ myPlace”等。哇,那些名称确实可以帮助我确定哪个。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.