是布尔值的方法参数不能接受? [关闭](Are booleans as method argum

2019-07-04 04:32发布

我的同事指出布尔方法参数是不能接受的 。 他们应由枚举所取代。 起初,我没有看到任何好处,但他给我举一个例子。

什么是更容易理解?

file.writeData( data, true );

要么

enum WriteMode {
  Append,
  Overwrite
};

file.writeData( data, Append );

现在我明白了! ;-)
这绝对是其中一个枚举作为第二个参数使代码更可读的例子。

那么,什么是你对这个话题的看法?

Answer 1:

布尔的代表“是/否”的选择。 如果你想表示一个“是/否”,然后用一个布尔值,它应该是不言自明的。

但是,如果它的两个选项,这两者都不是清晰地之间的选择是或否,然后枚举有时会更具可读性。



Answer 2:

枚举还允许将来的修改,你现在想要第三个选择(或更多)。



Answer 3:

使用一个最好的榜样您的问题。 在你给的例子中,枚举是一个更好的选择。 然而,会有其他时候,一个布尔是更好的。 这使得更多的意义给你:

lock.setIsLocked(True);

要么

enum LockState { Locked, Unlocked };
lock.setLockState(Locked);

在这种情况下,我可能会选择布尔的选择,因为我认为这是非常清楚和明确的,而且我敢肯定我的锁是不会有两个以上的状态。 尽管如此,第二选择是有效的,但不必要的复杂,恕我直言。



Answer 4:

我觉得你差不多这个回答自己,我认为最终目的是使代码更易读,在这种情况下,枚举这样做,IMO它总是最好看的最终目标,而不是毯子规则,可能会觉得它更作为一个准则,即枚举往往是代码不是一般的布尔变量,整型等更具可读性,但总会有例外的规则。



Answer 5:

记住史蒂文森的期间提出来佐林大使在联合国问题的古巴导弹危机 ?

“你是在世界舆论的法庭,现在,你可以回答是或不是 。你已经否认[导弹]存在,我想知道我是否正确地理解你....我准备等待我的回答,直到地狱冻结了,如果这是你的决定。”

如果你在你的方法具有标志是这样的性质,可以用别针把它降低到二元决策 ,并决定永远不会变成一个三方或n路的决定,去为布尔。 主治:你的旗帜被称为isXXX。

不要让它在的东西,是一个模式切换的情况下布尔值。 总有一个比你想在第一时间编写方法时的模式

在一个多模式的两难境地例如Unix的困扰,其中可能的许可模式的文件或取决于文件类型,所有制等目录可以在模式的怪异双重含义今天的结果



Answer 6:

对我来说,无论使用布尔也不枚举是一个不错的办法。 罗伯特C.马丁在他非常明确地抓住了这个干净的代码提示#12:消除布尔参数 :

布尔参数大声宣布这个功能确实不止一两件事。 他们是混乱的,应该被淘汰。

如果一个方法做多件事情,你应该写,而两种不同的方法,例如你的情况: file.append(data)file.overwrite(data)

用枚举不会让事情更清晰。 它不会改变任何东西,它仍然是一个标志参数。



Answer 7:

还有我碰到这是一件坏事,原因有二:

  1. 因为有些人会写的方法,如:

     ProcessBatch(true, false, false, true, false, false, true); 

    这显然是不好的,因为它太容易混淆的参数,你必须看它你指定什么也不知道。 只是一个布尔是不是太糟糕,但。

  2. 由于控制由简单的是程序流程/无分支可能意味着你有被包裹成一个在awkard方式两个完全不同的功能。 例如:

     public void Write(bool toOptical); 

    说真的,这应该是两个方法

     public void WriteOptical(); public void WriteMagnetic(); 

    因为这些代码可能是完全不同的; 他们可能不得不做各种不同的错误处理和验证,或者甚至有不同的格式输出数据。 你不能告诉,仅使用Write() ,甚至Write(Enum.Optical)不过当然你可以有两种这些方法只是调用内部方法,如果你想WriteOptical / MAG)。

我想这只是取决于。 我不会做太大的关于它的交易除了#1。



Answer 8:

枚举是更好,但我不会把布尔PARAMS是“不可接受的”。 有时,它只是更容易地抛出一个小布尔并继续前进(认为私有方法等)



Answer 9:

布尔可确定在已命名的参数,比如Python和Objective-C语言,因为名字可以解释参数做什么:

file.writeData(data, overwrite=true)

要么:

[file writeData:data overwrite:YES]


Answer 10:

我不同意,这是一个很好的规则 。 显然,枚举使得在某些情况下,更好地明确或冗长的代码,但作为一项规则,似乎大大超过深远。

首先让我把你的例子:程序员的责任(和能力)来编写好的代码是不是真的由具有布尔参数危害。 在您的例子中,程序员可以通过书面形式写了,就像冗长的代码:

dim append as boolean = true
file.writeData( data, append );

或者我更喜欢更普遍

dim shouldAppend as boolean = true
file.writeData( data, shouldAppend );

第二:你给枚举的例子是只有“更好”,因为你正在传递一个常量。 最有可能在大多数应用程序至少有一些即使不是大多数传递给函数的时间参数的变数。 在这种情况下,(给人以良好的名称变量)我的第二个例子是好多了,枚举就会给你一点好处。



Answer 11:

枚举有一定的好处,但你should't只是去替换枚举所有的布尔值。 有许多地方的true / false实际上是代表正在发生的事情的最好方法。

然而,使用它们的方法参数是有点怀疑,仅仅是因为你无法看到没有挖掘到的东西是什么,他们应该做的,因为他们让你看到什么真/假,其实就是

性能(特别是C#3对象初始值)或关键字参数(一拉Ruby或Python)是一个更好的方法去的地方,否则你使用布尔参数。

C#示例:

var worker = new BackgroundWorker { WorkerReportsProgress = true };

例如红宝石

validates_presence_of :name, :allow_nil => true

Python的例子

connect_to_database( persistent=true )

我能想到的,其中一个布尔方法的说法是正确的事情的唯一的事情是在Java中,你没有任何属性或关键字参数。 这是我最讨厌的java的原因之一:-(



Answer 12:

虽然这是事实,在许多情况下,枚举是更具可读性和比布尔更具扩展性,绝对的规则,即“布尔是不能接受的”,是愚蠢的。 这是缺乏灵活性,适得其反 - 它不留有余地,人的判断。 他们是内建类型的大多数语言的根本,因为它是有用的 - 考虑将其应用到其他内置类型:话说比如“从不使用int作为参数,”这纯粹是疯了。

此规则只是一个窃听器或运行时性能的作风问题,不是的潜力。 一个更好的规则是“宁可枚举到布尔的可读性的原因”。

看看.NET框架。 布尔被用作了不少方法的参数。 在.NET API是不完美的,但我不认为使用布尔作为参数是一个大问题。 工具提示始终为您提供了参数的名称,你可以建立这样的指导太 - 填写方法参数的XML注释,他们将拿出在工具栏中。

我还要补充一点,还有就是当你应该清楚地重构布尔为枚举的情况下 - 当你有两个或更多的布尔在你的类,或者在你的方法参数,可以和并非所有国家都有效(例如,它是不是有效的让他们这两个设置为true)。

举例来说,如果你的类有属性,如

public bool IsFoo
public bool IsBar

而且它有在同一时间他们两人真正的错误,你实际所得到的是三个有效的状态,更好地表现为类似:

enum FooBarType { IsFoo, IsBar, IsNeither };


Answer 13:

你的同事可能会得到更好的遵守一些规则:

  • 不要被教条与您的设计。
  • 选择什么最适合适合您的代码的用户。
  • 不要试图bash的星形钉到每一个孔就因为你这个月想的形状!


Answer 14:

布尔只会是可以接受的,如果你不打算延长框架的功能。 枚举是首选,因为你可以扩展枚举,而不是打破函数调用以前的实现。

枚举的另一个优点是易于阅读。



Answer 15:

如果该方法要求如一个问题:

KeepWritingData (DataAvailable());

哪里

bool DataAvailable()
{
    return true; //data is ALWAYS available!
}

void KeepWritingData (bool keepGoing)
{
   if (keepGoing)
   {
       ...
   }
}

布尔方法参数似乎使绝对完美的感觉。



Answer 16:

这取决于方法。 如果方法做一些事情,这是非常明显的真/假的东西,然后它是好的,例如低于[虽然不是我不说,这是该方法的最好的设计,这只是其中的用法是明显的例子。

CommentService.SetApprovalStatus(commentId, false);

然而,在大多数情况下,比如你提到的例子,最好是使用一个枚举。 有在.NET Framework本身许多例子这一惯例没有得到遵守,但那是因为他们在周期相当晚在介绍这一设计原则。



Answer 17:

它确实使事情更加明确,但并开始大规模扩展你的接口的复杂性 - 在一个纯粹的布尔选择,如附加/覆盖它似乎有点小题大做。 如果您需要添加更多的选项(我不能在这种情况下想到的),你可以随时进行重构(取决于语言)



Answer 18:

枚举肯定可以使代码更易读。 还有一些事情要注意(在.NET中至少)

因为enum的底层存储是一个int,默认值将是零,所以你应该确保0是一个合理的默认。 (如结构已创建时的所有字段设置为零,所以没有办法来指定0以外默认如果你没有一个0值,你甚至不能测试不枚举铸造为int,这将是不良作风。)

如果枚举的是私有的代码(从未公开曝光),那么你可以停止阅读这里。

如果您枚举发布以任何方式对外代码和/或保存在程序之外,可以考虑明确编号他们。 编译器会自动编号他们0,但如果你重新排列枚举没有给他们的值,可以有缺陷的结束。

我可以合法地写

WriteMode illegalButWorks = (WriteMode)1000000;
file.Write( data, illegalButWorks );

为了解决这个问题,消耗的枚举,你无法确定的任何代码(如公共API)需要检查枚举是有效的。 你可以通过做

if (!Enum.IsDefined(typeof(WriteMode), userValue))
    throw new ArgumentException("userValue");

的唯一要注意的Enum.IsDefined是,它使用反射和较慢。 它也遭受版本问题。 如果你需要经常检查枚举值,你会折以下更好:

public static bool CheckWriteModeEnumValue(WriteMode writeMode)
{
  switch( writeMode )
  {
    case WriteMode.Append:
    case WriteMode.OverWrite:
      break;
    default:
      Debug.Assert(false, "The WriteMode '" + writeMode + "' is not valid.");
      return false;
  }
  return true;
}

该版本的问题是,旧的代码可能只知道如何处理2个枚举你有。 如果添加第三个值,Enum.IsDefined将是真实的,但旧的代码不一定能够处理它。 哎呦。

甚至还有更多你可以做的乐趣[Flags]枚举,并为验证代码略有不同。

我还会注意到,对于便携性,你应该使用电话ToString()的枚举,并使用Enum.Parse()读取它们放回时,两者ToString()Enum.Parse()可以处理[Flags]枚举的作为好了,所以没有理由不使用它们。 你要知道,这是又一个陷阱,因为现在你甚至不能改变枚举的名称,而不可能断码。

所以,有时候你需要权衡上述所有当你问自己我可以逃脱只是一个布尔?



Answer 19:

恕我直言,这似乎是一个枚举会是两个以上的选项是可能的任何情况下的不二之选。 但肯定在哪里的布尔是你所需要的情况。 在这种情况下,我要说的是,使用一个枚举,其中一个布尔值,将工作将使用7个字4时会做的一个例子。



Answer 20:

布尔意义,当你有一个明显的切换只能是两件事情之一(即一个灯泡的状态,打开或关闭)。 除此之外,它的好,它写在这样一种方式,很明显你传递什么 - 例如,磁盘写入 - 无缓冲,行缓冲或同步 - 应为这样的传递。 即使你不希望允许同步写入,现在(所以你只限于两种选择),这是值得考虑让他们知道他们的第一眼做的目的更加详细。

这就是说,你也可以使用假和真(布尔值0和1),然后如果你以后需要更多的价值,功能扩展出来,支持用户自定义的值(比方说,2和3),和旧的0/1值将端口超过好听,所以你的代码不应该打破。



Answer 21:

有时,它只是简单的不同的行为与重载建模。 要继续从您的例子是:

file.appendData( data );  
file.overwriteData( data );

这种做法会降低,如果你有多个参数,允许每一套固定的选项。 例如,打开文件的方法可能具有的文件模式(打开/创建),文件访问(读/写)几个置换,共享模式(无/读/写)。 构的总数目等于的单个选项的笛卡尔积。 当然,在这种情况下,多个重载是不恰当的。

枚举可以,在某些情况下使代码的可读性,虽然确认在某些语言中的确切枚举值(C#例如)可能是困难的。

通常,一个布尔参数被追加到的参数作为一个新的重载列表。 在.NET中的一个例子是:

Enum.Parse(str);  
Enum.Parse(str, true); // ignore case

后者在过载比第一的.NET框架的更高版本面世。

如果你知道会有永远只能是两个选择,一个布尔值会被罚款。 枚举是不会打破旧的代码,虽然旧库可能不支持新的枚举值,所以版本不能完全忽视的方式扩展。


编辑

在C#的新版本有可能使用命名论点,IMO,可以使通话更清晰的代码以同样的方式,枚举可以。 使用与上述相同的例子:

Enum.Parse(str, ignoreCase: true);


Answer 22:

在哪里我不同意,枚举是要走好办法,当你有2个选项的方法(和只有两个选项,你可以有不枚举可读性。)

public void writeData(Stream data, boolean is_overwrite)

爱枚举,但布尔是有用的。



Answer 23:

这是旧的文章迟进入,它是那么的远了网页,没有人会读它,而是因为没有人已经表示,它....

内部注释,走一段很长的方式来解决意外bool问题。 原来的例子尤其令人发指:试想一下命名的功能declearation变量! 它会是这样的

void writeData( DataObject data, bool use_append_mode );

但是,例如起见,让我们说这是声明。 然后,对于其他原因不明布尔的说法,我在内部注释,把变量名。 相比

file.writeData( data, true );

file.writeData( data, true /* use_append_mode */);


Answer 24:

这真的取决于参数的确切性质。 如果它不是一个是/否或真/假然后枚举使它更具可读性。 但随着枚举你需要检查参数或具有可接受的默认行为,因为基础类型的不确定值可以通过。



Answer 25:

使用枚举,而不是在你的例子布尔值确实有助于使该方法调用更具可读性。 然而,这是在C#中我最喜欢的愿望项目,在方法调用命名参数的替代品。 此语法:

var v = CallMethod(pData = data, pFileMode = WriteMode, pIsDirty = true);

将是完全可读的,那么你可以做一个程序员应该做的事情,这是选对方法的每个参数的最合适的类型,而不考虑它的外观在IDE中。

C#3.0允许命名的构造函数的参数。 我不知道为什么他们不能做到这一点与方​​法为好。



Answer 26:

布尔值true / false而已。 因此,目前还不清楚是什么代表。 Enum可以有有意义的名称,如OVERWRITEAPPEND等,所以枚举更好。



文章来源: Are booleans as method arguments unacceptable? [closed]