命名参数(参数)作为可读性的帮助


11

很久以前,我在ADA中编写了很多程序,调用函数时为参数命名是很正常的-SomeObject.DoSomething(SomeParameterName => someValue);

既然C#支持命名参数,我正在考虑在参数的含义可能不太明显的情况下恢复这种习惯。

您可能会争辩说参数的含义应该总是很明显,但是如果您具有布尔参数,并且调用者传递的是“ true”或“ false”,则用名称限定值可以使调用站点更具可读性。

contentFetcher.DownloadNote(note,manual:true);

我想我可以创建枚举而不是使用true或false(在这种情况下为Manual,Automatic)。

您如何偶尔使用命名参数使代码更易于阅读?


方法顶部的参数注释也有帮助。
阿米尔·雷扎伊

1
@ amir-rezaei:仅当您可以信任注释时,方法顶部的参数注释才有用。除非您有优秀的开发人员良好的代码审查流程,否则我不会相信这些评论。
btilly

作为我自己的Ada一次性用户,我偶尔会像您描述的那样使用。这就是我记得它们在Ada,BTW中使用的方式-我不会将其称为“异常”,但“正常”一词似乎暗示大多数调用都将指定参数名称,而这并不是我记住的方式。当然,约定会有所不同,但是在任何IMO语言中,不必要的混乱都是不好的约定。
Steve314 2011年

我同意您在Ada中的使用-这不是我们一直都在做的事情,但是有帮助。
Damian

Answers:


7

这是在C ++的开发中提出的,Stroustrup在他的“ C ++的设计和演进”(第153页及以后)中对此进行了讨论。该提案格式合理,并借鉴了Ada的以往经验。没有被采纳。

最大的原因是没有人愿意鼓励带有大量参数的功能。语言中的每个附加功能都需要花费一些钱,因此不希望添加功能以使其更容易编写不良程序。

它还提出了关于规范参数名称是什么的问题,尤其是在通常的标头和代码文件约定中。一些组织在.h文件中具有更长和更具描述性的参数名称,而在.cpp文件中具有更短,更容易键入名称(根据需要替换文件后缀)。要求它们相同将是编译的额外费用,并且在源文件之间混用名称可能会引起细微的错误。

也可以使用对象而不是函数调用来处理它。而不是使用带有十二个参数的GetWindow调用,而是创建带有十二个私有变量的Window类,并根据需要添加setter。通过链接设置器,可以编写类似的内容my_window.SetColor(green).SetBorder(true).SetBorderSize(3);。也可能有具有不同默认值的不同函数,这些默认函数调用实际起作用的函数。

如果您只是担心的文档编制效果contentFetcher.DownloadNote(note, manual : true);,则可以随时编写类似的内容contentFetcher.DownloadNote(note, /* manual */ true);,因此它甚至对文档编制没有太大帮助。


有趣的是,当我从Ada转到C时,我开始使用您所描述的约定-代码审查员对此很讨厌。同意不要将其用于大量参数。
Damian

7

我认为这是使不良代码更具可读性的问题,而不是“最佳实践”。

有一个采用20个参数的方法(或承包商)是“难闻的气味”,很可能是由于设计中的问题所致。但是,如果在方法带有大量参数的情况下我不得不处理代码,那么命名参数会使代码难于理解。

当方法仅具有1或2个参数并且从方法名称可以清楚地知道该参数是什么时,则命名参数将不添加任何内容。 这是理想的情况。

如果您使用的所有代码都写成“ 干净的代码 ”书,那么您将很少使用命名参数,但是我们生活在现实世界中。


1
如果两个参数的类型相同且不知道哪个参数,则带有两个参数的函数可能会造成混淆。当然,您可以通过提供线索的方式来命名函数,但是实际上,无论如何,您实际上只是在执行参数名的操作-除了即使在上下文中(例如,提供参数),以便清楚地知道哪个参数是哪个。
Steve314,2011年

1
@ Steve314示例:void TrackDataChange(Data oldData, Data newData)
亚历山大

3

我同意添加参数名称使其更具可读性。但是,我读过的大多数书似乎都认为布尔开关是一种不好的做法。我有时会这样做:

public Content DownloadNote(Note note)
{
    return downloadNote(note, manual: false);
}

public Content DownloadNoteManually(Note note)
{
    return downloadNote(note, manual: true);
}

这确实为您提供了实现API时的更大灵活性。它还允许您控制具有多个布尔开关的情况,但是并非所有布尔开关都可以同时处于活动状态。


3
如果您有x个选择,您会做2 ^ x个前端吗?
apoorv020 2011年

@ apoorv020-如果我有足够的参数来进行2 ^ x的方法调用,那么我将创建一个新类来保存参数值,并只传递一个参数。
斯科特·惠特洛克

@ scott-whitlock:选项1-创建一个对象,设置x个属性,然后用对象调用一次方法。选项2-调用带有x个命名参数的方法。哪个更好取决于您的语言。在动态类型语言中,选项1需要大量的样板,而没有增益,因此更糟。在静态类型语言中,您仍然可以添加样板,但是对不正确命名的键的测试必须在编译时而不是运行时完成。因此,选项1在C#中更好,而选项2在Python中是一个明显的胜利。
btilly 2011年

@btilly-正如Ian所指出的那样,Clean Code清楚地告诉您,具有超过2个或3个参数的函数。公平地说,它正在处理静态类型的Java。OP还询问有关静态类型的C#的问题。与一长串参数相比,我还是更喜欢使用函数重载和/或使用其他精确命名的函数名称。
Scott Whitlock

@ scott-whitlock:我们实际上不同意吗?我们同意C#的优点。我们俩都知道Clean Code所说的话。我的观点是,重要的是要理解它的好处,以便您知道建议何时适合或不适合其他环境。
btilly 2011年

3

在方法的名称和类型和语义不清楚的情况下,我非常相信命名参数。我的经验是很少有人阅读该文档。

话虽这么说,命名参数不应该替代使用合理的参数列表,使用帮助对象(将语义相关的参数“绑定”在一起)以及在相关时使用枚举。


0

我认为这在非​​OO语言中更有用,在非OO语言中,您可能具有一个必须以几种略有不同的方式执行某项功能的功能,并且该功能确定其操作方式的依据是参数值。在OOP世界中,我们只会重载该函数,但是在不可能的情况下,您最终会传递一堆标志(或一堆值,以及是否传递这些标志)。

我认为它在某种程度上更具可读性;但是正如其他人所提到的那样,具有许多参数是代码的味道,因此在C#之类的面向对象的语言中,我看不到有太多使用。

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.