【问题标题】:Should I use `!IsGood` or `IsGood == false`?我应该使用 `!Is Good` 还是 `Is Good == false`?
【发布时间】:2010-09-26 06:05:15
【问题描述】:

我不断看到这样的检查代码

if (IsGood == false)
{
   DoSomething();
}

或者这个

if (IsGood == true)
{
   DoSomething();
}

我讨厌这种语法,总是使用以下语法。

if (IsGood)
{
   DoSomething();
}

if (!IsGood)
{
   DoSomething();
}

有什么理由使用“== true”或“== false”吗?

这是一个可读性的东西吗?人们只是不理解布尔变量吗?

另外,两者在性能上有区别吗?

【问题讨论】:

  • 如果这真的让你如此烦恼,那对你来说将是漫长而艰难的生活。
  • 这是一个公平的问题,OP 对我来说似乎并不太生气。
  • 是的,它是有效的。我不时用简单的事情怀疑自己,偶尔会找到一个很好的理由来改变我的方式......
  • 克里斯,这不是分支结构的问题。 C 是类型化的,但它没有布尔类型。 “if(good)”不同于“if(good == TRUE)”。第一个意味着好是非零的。第二个意思是good正好等于TRUE,这是一个特定的整数值。有关更多信息,请参阅 MikeB 的答案。
  • 在我看来主要问题是它让开发人员看起来好像他们并不真正理解布尔值

标签: language-agnostic boolean not-operator


【解决方案1】:

我的语法和你一样,不那么冗长。

人们(更多是初学者)更喜欢使用== true,只是为了确保这是他们想要的。他们习惯于在条件中使用运算符……他们发现它更具可读性。但是一旦你变得更高级,你会发现它很烦人,因为它太冗长了。

【讨论】:

  • 不只是初学者喜欢它;任何对最大化代码可读性感兴趣的人都喜欢它。费用是多少?
  • 我发现它更短的方式更具可读性......当左侧已经是真/假时,右边的目标是什么==真......不要说“任何人”......我同意 Daok,几个月前我就这样做了,而不是意识到我的错误
  • 如果您正确命名变量,那么添加运算符实际上会降低可读性。 IE。当您阅读它时,“如果好”比“如果好就是真的”更具可读性。我选择“if (isGood)”,它尽可能清晰。
  • 56 票赞成几乎微不足道的意见?哈,这个网站失控了。
  • 当我看到布尔类型的 == 时,我认为这表明使用 == 的人确实完全理解布尔逻辑及其含义。
【解决方案2】:

当我遇到时,我总是轻笑(或向某人扔东西,这取决于我的心情)

if (someBoolean == true) { /* ... */ }

因为如果你不能依赖于你的比较返回布尔值这一事实,那么你也不能依赖于将结果与 true 进行比较,所以代码应该变成

if ((someBoolean == true) == true) { /* ... */ }

但是,当然,这真的应该是

if (((someBoolean == true) == true) == true) { /* ... */ }

但是,当然……

(啊,编译失败。恢复工作。)

【讨论】:

  • Shades of Monty Python and the Spam sketch... 我想要一个包含 Spam、Spam、Spam、true 和 Spam 的 If 测试.....
【解决方案3】:

我更喜欢较短的变体。但有时== false 有助于使您的代码更短:

对于使用 C# 2.0 的项目中的实际场景,我认为只有一个很好的理由这样做:bool? 类型。三态bool? 很有用,通过这种方式很容易检查它的一个可能值。

如果IsGoodbool?,实际上你不能使用(!IsGood)。但是写(IsGood.HasValue && IsGood.Value)(IsGood == true)差。

玩这个示例以获得想法:

bool? value = true; // try false and null too

if (value == true)
{
    Console.WriteLine("value is true");
}
else if (value == false)
{
    Console.WriteLine("value is false");
}
else
{
    Console.WriteLine("value is null");
}

我刚刚发现了另一种情况,if (!IsGood) { ... }if (IsGood == false) { ... } 不同。但是这个是不现实的 ;) 运算符重载在这里可能会有所帮助 :) (和运算符 true/false AFAIK 在 C# 2.0 中是不鼓励的,因为它的预期目的是为用户定义的类型提供类似 bool? 的行为,现在你可以用标准类型得到它!)

using System;

namespace BoolHack
{
    class Program
    {
        public struct CrazyBool
        {
            private readonly bool value;

            public CrazyBool(bool value)
            {
                this.value = value;
            }

            // Just to make nice init possible ;)
            public static implicit operator CrazyBool(bool value)
            {
                return new CrazyBool(value);
            }

            public static bool operator==(CrazyBool crazyBool, bool value)
            {
                return crazyBool.value == value;
            }

            public static bool operator!=(CrazyBool crazyBool, bool value)
            {
                return crazyBool.value != value;
            }

            #region Twisted logic!

            public static bool operator true(CrazyBool crazyBool)
            {
                return !crazyBool.value;
            }

            public static bool operator false(CrazyBool crazyBool)
            {
                return crazyBool.value;
            }

            #endregion Twisted logic!
        }

        static void Main()
        {
            CrazyBool IsGood = false;

            if (IsGood)
            {
                if (IsGood == false)
                {
                    Console.WriteLine("Now you should understand why those type is called CrazyBool!");
                }
            }
        }
    }
}

所以...请谨慎使用运算符重载:(

【讨论】:

  • (IsGood == true) 也不起作用,如果 IsGood 是一个可为空的布尔值。您必须编写 (IsGood.HasValue && IsGood.Value == true),这仍然比 (IsGood.HasValue && IsGood.Value) 更冗长且可能不太清晰
  • 查尔斯,我认为你错了。对于 Nullable 您将获得 T 作为属性 Value 的类型(在我们的例子中是 bool,所以 (... && IsGood.Value) 应该可以工作)。你也可以使用最短的形式。尝试使用我刚刚添加的示例来回答。
  • IgorK,我同意,[IsGood.Value] 会起作用,(如果 IsGood 有值...) > 在这种情况下 IsGood 不是 bool,它是 Nullable 所以你不能将它与“true”进行比较,这会导致类型不匹配
  • Charles,第一个示例适用于所有三种情况(当 IsGood 类型化 bool? 初始化为 true、false 或 null 时)。我又检查了一次。您是说第一个示例不会使用 C# 2.0 编译器进行编译吗?它实际上确实......在空情况下也没有例外:)
  • 我更喜欢 if(IsGood.GetValueOrDefault()),它具有相同的效果并且比 if(IsGood.HasValue && IsGood.Value) 更快(执行时间)。请注意 if(!IsGood.GetValueOrDefault()) 与 if(IsGood.HasValue && !IsGood.Value) 不同。
【解决方案4】:

根据Code Complete 一本书Jeff got his name from 并高度重视以下是您应该处理布尔值的方式。

if (IsGood)
if (!IsGood)

我习惯于实际比较布尔值,但我想为什么要在该过程中添加一个额外的步骤并将布尔值视为二流类型。在我看来,比较返回一个布尔值,而布尔类型已经是一个布尔值,所以为什么不直接使用布尔值。

真正的争论归结为为您的布尔值使用好名字。就像你在上面所做的那样,我总是用问题的 for 来表达我的布尔对象。比如

  • 很好
  • 有值

【讨论】:

    【解决方案5】:

    如果所讨论的变量真的应该用作布尔值(即使它的类型不是布尔值),那么专门针对真假进行测试的技术绝对是不好的做法——尤其是在 C/C++ 中。针对true 的测试可能(并且可能会)导致细微的错误:

    这些明显相似的测试给出相反的结果:

    // needs C++ to get true/false keywords
    // or needs macros (or something) defining true/false appropriately
    int main( int argc, char* argv[])
    {
        int isGood = -1;
    
        if (isGood == true) {
            printf( "isGood == true\n");
        }
        else {
            printf( "isGood != true\n");
        }
    
        if (isGood) {
            printf( "isGood is true\n");
        }
        else {
            printf( "isGood is not true\n");
        }
    
        return 0;
    }
    

    这将显示以下结果:

    isGood != true
    isGood is true
    

    如果您觉得需要针对 true/false 测试用作布尔标志的变量(我认为不应该这样做),您应该使用始终针对 false 进行测试的习惯用法,因为 false 只能有一个值 (0) 而 true 可以有多个可能的值(0 以外的任何值):

    if (isGood != false) ...  // instead of using if (isGood == true)
    

    有些人会认为这是 C/C++ 中的一个缺陷,这可能是真的。但在这些语言(可能还有许多其他语言)中,这是生活中的事实,所以我会坚持使用简短的习语,即使在 C# 等不允许您将整数值用作布尔值的语言中也是如此。

    请参阅此 SO 问题以了解此问题实际咬人的示例...

    【讨论】:

      【解决方案6】:

      我同意你的看法(我也对此感到恼火)。我认为IsGood == true 计算为bool 只是一个小小的误解,这就是IsGood 的开始。

      我经常看到SomeStringObject.ToString() 的这些邻近实例。

      也就是说,在使用类型较宽松的语言中,这可能是合理的。但不是在 C# 中。

      【讨论】:

      • 这个出现在 String.ToString() 附近的好点,但我很想知道对于一些习惯于数据类型较宽松的语言的开发人员来说,这是否是一种习惯的力量.
      • 对它评估为布尔值是正确的,这就是你开始的。那你停在哪里? ((isGood == false) == true)?不,这也是一个布尔值,(((isGood == false) == true) == true) 等等......将布尔值与布尔值进行比较只是意味着你做错了......:p
      【解决方案7】:

      有些人发现对已知值的显式检查更具可读性,因为您可以通过阅读来推断变量类型。我不知道一个是否比另一个更好。他们都工作。我发现如果变量固有地持有一个“逆”,那么我似乎倾向于检查一个值:

      if(IsGood) DoSomething();
      

      if(IsBad == false) DoSomething();
      

      而不是

      if(!IsBad) DoSomething();
      

      但同样,这对我来说并不重要,而且我确信它最终会成为同一个 IL。

      【讨论】:

      • 这就是我所做的。如果我正在寻找一个错误,我会做一个 == false,但我尽量不这样做。我宁愿根本不反转条件。将 isBad 重构为 isGood 通常更有意义,或者交换 if/else 块以使其更有意义,或其他任何方式。
      • 如果你看到 if(IsGood) 你也可以推断它是一个布尔值,否则它不会编译! ;) 无论如何,你是对的,初学者往往会以这种方式更清楚地看到它。
      【解决方案8】:

      仅可读性..

      如果您喜欢的任何方式在编译成机器代码时效率更高。但是我希望它们产生完全相同相同的机器代码。

      【讨论】:

        【解决方案9】:

        从目前的答案来看,这似乎是共识:

        1. 在大多数情况下,短格式是最好的。 (IsGood 和 !IsGood)
        2. 布尔变量应写为正数。 (IsGood 而不是 IsBad)
        3. 由于大多数编译器会以任一方式输出相同的代码,因此没有性能差异,解释型语言除外。
        4. 这个问题没有明确的赢家,可能被视为编码风格的宗教战争。

        【讨论】:

        • 我不同意没有明确的赢家——尤其是在 C/C++ 中。这不仅仅是风格问题,可能存在语义差异。使用较长的形式可能会导致细微的错误。
        • 但使用较长的形式会导致细微的错误。 if (isGood = false) 可以通过使用 ! 来避免
        【解决方案10】:

        我更喜欢使用:

        if (IsGood)
        {
            DoSomething();
        }
        

        if (IsGood == false)
        {
            DoSomething();
        }
        

        因为我发现这更具可读性 - !太容易错过(在阅读和打字方面);还有“if not IsGood then...”听起来不太对劲,而不是“if IsGood is false then...”听起来更好。

        【讨论】:

          【解决方案11】:

          有可能(尽管不太可能,至少我希望如此)在 C 代码中 TRUE 和 FALSE 被 #定义为 1 和 0 以外的东西。例如,程序员可能决定使用 0 作为“真”和 -1在特定 API 中为“假”。遗留 C++ 代码也是如此,因为“true”和“false”并不总是 C++ 关键字,尤其是在 ANSI 标准出现之前。

          还值得指出的是,某些语言——尤其是像 Perl、JavaScript 和 PHP 这样的脚本语言——可以对哪些值视为真、哪些值视为假有有趣的解释。 “foo == false”的含义可能与“!foo”有细微的不同(尽管希望不大)。这个问题被标记为“语言不可知论”,一种语言可以定义 == 运算符,使其不能以与 ! 兼容的方式工作。运算符。

          【讨论】:

          • 在 C/C++ 中还有一些微妙的行为,其中任何非零都是“真”但不一定 == 真。
          【解决方案12】:

          我已将以下内容视为 C/C++ 样式要求。

          if ( true == FunctionCall()) {
            // stuff
          }
          

          原因是如果你不小心把“=”而不是“==”,编译器将放弃为常量赋值。同时,它会损害每个 if 语句的可读性。

          【讨论】:

          • 我没有关注这个。如果你不需要'==',你不会不小心输入'='
          • 这实际上有助于提高可读性(在习惯它之后(不需要很长时间))。始终建议将较短的项目放在开头(SomLongFunctionCall(*pointer[3], file == NOFILE, GetMyHeap(1, ALWAYS)) == E_NOERR很多相反的方式:E_NOERR == SomLongFunctionCall(*pointer[3], NOFILE == file, GetMyHeap(1, ALWAYS))。YMMV 像往常一样。
          【解决方案13】:

          有时它在可读性方面有用途。有时,命名变量或函数调用最终可能会成为双重否定,这可能会造成混淆,并且像这样使预期的测试明确有助于提高可读性。

          一个很好的例子可能是 strcmp() C/C++ 如果字符串相等则返回 0,否则返回 0,具体取决于差异所在的位置。所以你会经常看到:

          if(strcmp(string1, string2)==0) { /*do something*/ }
          

          不过我同意你的观点

          if(!isCached)
          {
              Cache(thing);
          }
          

          阅读起来更清晰。

          【讨论】:

          • 一旦你理解了 strcmp 就更好了 if( !strcmp(string1, string2) ) { /*do something*/ }
          • 执行 !strcmp 更糟糕,因为您将逻辑运算符与非逻辑值混合在一起。 strcmp==0/!=0 是更正确、更清晰的方法。
          • 过去我遇到过 strcmp 的麻烦,因为我没有完全理解它返回的内容,主要是因为它在大多数地方被用作 !strcmp() 。总的来说,我发现写 ==0 并没有那么冗长,而且它绝对明确地表明了你对它的期望。
          • 通常我使用一个名为 isEqual 的内联函数或宏,它调用 !strcmp。事实上,在我的 C++ 代码中,我现在使用一个名为 cStrBuff 的 char* 包装类,它具有实用函数和运算符。
          • 与 strcmp 类似,如果以布尔方式测试非布尔变量,如下所示: if(count) {count--;} 我总是需要额外的时间才能意识到 count 不是布尔值,我们在这里测试其他东西。
          【解决方案14】:

          我更喜欢 !IsGood 方法,而且我认为大多数具有 c 风格语言背景的人也会更喜欢它。我只是在这里猜测,但我认为大多数编写 IsGood == False 的人都来自像 Visual Basic 这样更冗长的语言背景。

          【讨论】:

          • 在 Visual Basic 中更是如此,“Not IsGood”比“IsGood = False”更具可读性
          【解决方案15】:

          只有更糟糕的是

          if (true == IsGood) {....
          

          从不理解这种方法背后的想法。

          【讨论】:

          • 我认为它来自 C++。如果你写错了'if (x = 6)',那么这个bug就很难找到了,而'if (6 = x)'会导致编译错误。
          • 一旦你习惯了看它,阅读它就没有问题。有点像习惯阅读英语?
          • 我讨厌看到这个。你不会说,“红色是汽车的颜色”,除非你听起来很深沉或很花哨。你只会说,“这辆车的颜色是红色的。”
          【解决方案16】:

          !IsGood 模式在简化为正则表达式时比 IsGood == false 更容易找到。

          /\b!IsGood\b/
          

          /\bIsGood\s*==\s*false\b/
          /\bIsGood\s*!=\s*true\b/
          /\bIsGood\s*(?:==\s*false|!=\s*true)\b/
          

          【讨论】:

            【解决方案17】:

            为了可读性,您可以考虑一个依赖于另一个属性的属性:

            public bool IsBad => !IsGood;
            

            那么,你就可以真正理解这个意思了:

            if (IsBad)
            {
                ...
            }
            

            【讨论】:

            • 这实际上是我最讨厌的事情之一。在某个地方,我被告知布尔值应该代表积极的条件。使用否定条件不可避免地会导致奇怪的双重否定测试,例如“if (!IsBad || !Uninitialized)”将开发人员的大脑放入温和的椒盐脆饼中。
            • 但是,如果你有推论 IsGood 和 IsBad,那么你就不需要做类似 !IsBad 之类的事情
            • 如果你喜欢你的堆栈溢出异常... public bool IsBad { get { return !IsGood; } } public bool IsGood { get { return !IsBad; } }
            • 如果您忘记了IsBad 是一个属性或其他东西怎么办? !IsGood 应该读作 Is not Good 所以它是内置的
            【解决方案18】:

            我更喜欢!IsGood,因为对我来说,它更清晰简洁。检查 boolean == true 是否是多余的,所以我会避免这种情况。虽然在语法上,我认为检查 IsGood == false 是否有区别。

            【讨论】:

            • 我认为您的意思是“语义上”。严格来说,它们之间存在差异,因为使用的运算符(包括 false)可以被覆盖。此外(取决于您的语义级别),两者都描述了不同的评估(尽管编译器很可能对两者使用相同的评估)。
            【解决方案19】:

            在许多语言中,不同之处在于,在一种情况下,您让编译器/解释器决定真假的含义,而在另一种情况下,它由代码定义。 C 就是一个很好的例子。

            if (something) ...
            

            在上面的示例中,“某事”与编译器对“真”的定义进行了比较。通常这意味着“不为零”。

            if (something == true) ...
            

            在上面的示例中,“something”与“true”进行了比较。 “true”的类型(以及可比性)和“true”的值可能由语言和/或编译器/解释器定义,也可能不定义。

            通常两者并不相同。

            【讨论】:

              【解决方案20】:

              你忘了:

              if(IsGood == FileNotFound)

              【讨论】:

                【解决方案21】:

                在我看来(虽然我没有证据支持这一点)开始使用 C#/java 类型语言的人更喜欢“if (CheckSomething())”方法,而开始使用其他语言(C++)的人:特别是 Win32 C++)出于习惯倾向于使用其他方法:在 Win32 中,如果 CheckSomething 返回 BOOL(而不是 bool),“if (CheckSomething())”将不起作用;在许多情况下,API 函数显式返回 0/1 int/INT 而不是真/假值(这就是 BOOL)。

                再次,出于习惯,我总是使用更冗长的方法。它们在语法上是相同的;我不相信“冗长使我恼火”的废话,因为程序员不是需要被代码打动的人(计算机需要)。而且,在现实世界中,查看我编写的代码的任何特定人员的技能水平都会有所不同,而且我没有时间或意愿向可能不了解一点不重要的人解释语句评估的特殊性像这样的。

                【讨论】:

                • 编译器不关心代码。程序员(更重要的是后来的程序员)需要留下深刻的印象。你可以扔掉所有的格式和样式规则,编译器不会被打扰,但是任何阅读代码的人都会受到巨大的精神伤害
                【解决方案22】:

                啊,我有一些同事喜欢较长的形式,认为它比微小的更易读!

                我开始“修复”这个问题,因为布尔值是自给自足的,所以我放弃了十字军东征...... ^_^ 他们不喜欢在这里清理代码,无论如何,他们认为这使得分支之间的集成变得困难(那是是的,但是你永远生活在丑陋的代码中......)。

                如果你的布尔变量名写得正确,它应该是自然的:
                if (isSuccessful) vs. if (returnCode)

                在某些情况下,我可能会沉迷于布尔比较,例如:
                if (PropertyProvider.getBooleanProperty(SOME_SETTING, true) == true),因为它读起来不那么“自然”。

                【讨论】:

                  【解决方案23】:

                  出于某种原因,我一直很喜欢

                  if (IsGood)
                  

                  超过

                  if (!IsBad)
                  

                  这就是为什么我有点喜欢 Ruby 的除非(但它有点太容易被滥用):

                  unless (IsBad)
                  

                  如果像这样使用甚至更多:

                  raise InvalidColor unless AllowedColors.include?(color)
                  

                  【讨论】:

                    【解决方案24】:

                    Cybis,在使用 C++ 编码时,您还可以使用 not 关键字。这是很久以前的标准的一部分,所以这段代码是完全有效的:

                    if (not foo ())
                       bar ();
                    

                    编辑:顺便说一句,我忘了提到该标准还定义了其他布尔关键字,例如 and (&&)、bitand (&)、or (||), bitor (|), xor (^)...它们被称为运算符的同义词。

                    【讨论】:

                    • 你每天都会学到新东西。我读过大量的 C++ 文章、教程、书籍,在大学里上过 C++ 导向的课程,但以前从未见过这种语法。谢谢。
                    • 那位 VB 家伙加入 C++ 标准委员会时一定发生过这种情况!
                    • @P Daddy:是的,早在 1980 年代,当 Bjarne Stroustrup 设计 C++ 时,他借用 Knuth 的时间机器跳到了 90 年代,当时人们对 VB 程序员嗤之以鼻。或者您可能从未听说过 ALGOL
                    【解决方案25】:

                    如果你真的认为你需要:

                    if (Flag == true)
                    

                    那么由于条件表达式本身是布尔值,您可能希望将其扩展为:

                    if ((Flag == true) == true)
                    

                    等等。这棺材还需要多少钉子?

                    【讨论】:

                      【解决方案26】:

                      如果你碰巧在 perl 中工作,你可以选择

                      unless($isGood)
                      

                      【讨论】:

                      • 这似乎不如!isGood理想
                      【解决方案27】:

                      我不使用==,但有时我使用!=,因为它在我的脑海中更加清晰。但在我的工作中,我们不使用!===。如果使用hasXYZ()isABC(),我们会尝试获取一个有意义的名称。

                      【讨论】:

                        【解决方案28】:

                        就个人而言,我更喜欢 Bob 大叔在 Clean Code 中谈到的形式:

                        (...)
                            if (ShouldDoSomething())
                            {
                                DoSomething();
                            }
                        (...)
                        
                        bool ShouldDoSomething()
                        {
                            return IsGood;
                        }
                        

                        除了最琐碎的条件之外,条件句都放在谓词函数中。那么布尔表达式的实现的可读性就无关紧要了。

                        【讨论】:

                        • 我不想去其他地方了解“ShouldDoSomething”的含义。
                        • 我不同意上面的评论。通常人们会从工作流的角度来考虑,这在很多情况下比条件实现本身更重要。
                        • 我的观点完全正确。如果您考虑在查看代码时花费的脑力,那么当您不关心太多细节时,您会节省一些。
                        • 如果语句的主体只是“做某事”,为什么你需要条件是“如果应该做某事”......这很明显。除非在其他地方使用相同的条件,否则我认为这是不必要的。
                        • 这太愚蠢了。为什么要在堆栈上抛出另一个函数只是为了返回一个可以很容易直接使用的变量?这是一个简单的方法,您不妨将其设为仅get 的属性,但这只会返回IsGood,因此您不妨直接使用它,而不要让读者担心ShouldDoSomething 是一种昂贵的方法
                        【解决方案29】:

                        我们倾向于在这里做以下事情:

                        if(IsGood)
                        

                        if(IsGood == false)
                        

                        原因是我们有一些遗留代码由一个不再在这里(在 Delphi 中)的人编写,看起来像:

                        if not IsNotGuam then
                        

                        这在过去给我们带来了很大的痛苦,所以我们决定总是尝试检查阳性;如果这不可能,则将否定与错误进行比较。

                        【讨论】:

                          【解决方案30】:

                          我唯一能想到更冗长的代码有意义的地方是在 .NET 之前的 Visual Basic 中,其中 true 和 false 实际上是整数(true=-1,false=0),如果布尔表达式被评估,则被认为是 false对于任何其他非零值为零和真。因此,在旧 VB 的情况下,列出的两种方法实际上并不等效,如果您只希望某些东西在评估为 -1 时为真,则必须明确比较“真”。因此,如果计算为整数(因为它不为零),则计算结果为“+1”的表达式将为真,但它不等于“真”。我不知道为什么 VB 是这样设计的,但我看到很多布尔表达式在旧的 VB 代码中将变量与真假进行比较。

                          【讨论】:

                            猜你喜欢
                            • 2012-12-24
                            • 2022-06-14
                            • 1970-01-01
                            • 2010-11-15
                            • 2023-04-05
                            • 2022-01-03
                            • 2015-03-22
                            • 2018-10-15
                            • 2014-07-13
                            相关资源
                            最近更新 更多