【问题标题】:Why does C# && and || operators work the way they do?为什么 C# && 和 ||运营商的工作方式?
【发布时间】:2011-07-09 09:04:08
【问题描述】:

这里有一个 tl;dr

我来自 C++ 背景。 && 假设检查左侧是否为真,右侧是否为真。 & 与此有什么关系?为什么在 && 逻辑中使用它?


我听不懂http://msdn.microsoft.com/en-us/library/aa691312%28v=vs.71%29.aspx 并问了一个问题。我花了很长时间才理解并接受这个答案。我必须做很多后续阅读How does operator overloading of true and false work?

操作 x && y 被评估为 T.假(x)? x : T.&(x, y)

到底为什么要这样做?如果 false 重载返回 true 并且 true 运算符返回 true 则根本不计算 y。卧槽!!!!

我还是不明白。因为这对我来说太奇怪了,所以我花了一段时间才理解另一个问题的答案。在 C# 中,v = 1 && 2; 不起作用,因为您不能在整数上执行 &&。在 C 中,这返回 true(此处为代码/示例 http://codepad.org/9iCaqzQ2)。如果我们遵循上面的操作规则,我们会这样做

(使用 1 && 2)

  • Int.False(1) 为假
  • 1 & 2 (== 0)
  • Int.True(0) (== false)

这会让你得到错误的结果。

那么... C# 以这种方式使用 &&(和 ||)运算符的原因是什么。

【问题讨论】:

  • 请花一些时间来改进文章。无法理解你想问什么。
  • @archer 这是很自然的事情。如果一种语言与旧语言的做法不同,它通常有这样做的理由。为了与众不同而与众不同通常不是一个好主意。了解某事为何如此运作几乎与了解某事如何运作一样重要。
  • @CodeInChaos:正是 CodeInChaos。我想知道为什么你是唯一一个告诉我为什么事情实际上不同的人,而不是说“不,你做错了”和“你在说什么”-_-。我对每个人都很失望。
  • 我是在知道pascal之后才学c的。 Pascal 只有一个 and 运算符,它在布尔值上是逻辑(和短路),在整数上是二进制。因此,当切换到 c 时,我遇到了与您相反的问题。为什么 c 没有布尔值并使用两种 and 来代替?你可以习惯这样的事情,以至于你不再质疑为什么。如果您从 && 是短路的定义开始,那么您的问题没有意义,如果您从逻辑 vs 二进制开始。
  • 然后是工程师 vs 科学家,“怎么样?” vs“为什么?”。我的价值之一是“为什么?”高得多。如果您知道为什么通常变得微不足道。这样做的另一面是,我很难使用我不太了解的东西。

标签: c#


【解决方案1】:

&& 被定义为短路操作符;如果第一个操作数评估为假,则要求在此处短路而不评估右侧。您期望它还能做什么?这允许像if(arg != null && arg.Foo) {...} 这样的检查。

您的问题基本上是说“如果我编写了一个不正确的真/假运算符实现,就会发生坏事”......所以;不要那样做!要么不写真/假运算符根本,或者如果你这样做;做对了...

还有&|短路。

【讨论】:

  • 这就是我感到困惑的地方。假设我为 int 编写了这个,并希望在评估 0 时返回 false。我要在 false 运算符上返回 true?这就是为什么在我上面的示例步骤中,我在第一步的 false 运算符中返回 false(int.false(1),导致其为 true。我假设当 true 和 false 都返回 false 时,它​​被认为是 null。)
  • @acidzombie24 好吧,如果你混淆了按位逻辑和布尔逻辑,就会发生不好的事情......而且?
  • 我还是一头雾水。好的,这个怎么样。我来自 C++ 背景。 && 假设检查左侧是否为真,右侧是否为真。 & 与此有什么关系?为什么在 && 逻辑中使用它
  • 它只会在左侧为真时检查双方是否为真。如果左侧为 false,则返回 false 并且不检查右侧...
  • @acidzombie - 具体来说,& 作为按位运算符不支持满足布尔逻辑的必要条件,即您不知道x==truey==true 表示@ 987654327@,以12 作为反例。
【解决方案2】:

据我了解,您希望 a && b 被定义为 ((bool)a)&&((bool)b) 之类的东西,而不是 C# 使用的东西。

但我认为引入这种运算符重载是为了支持三态布尔值,例如 bool?DBBool

让我们为这种类型定义几个示例:

不可能发生短路:

null && true == null
null && false == false
null || true == true
null || false == null

可能发生短路:

false && null == false
true || null == true

这里的基本思想是将 null 视为未知值,如果结果未确定,则返回 null,如果无论您将什么放入 null 参数,结果都不会改变,则返回 bool。

现在您要在此类型上定义短路逻辑andor。如果您使用 C# truefalse 运算符执行此操作,这两个运算符都在 null 参数上返回 false,您将获得所需的行为。对于 c 类行为,您不会这样做。

C# 设计者可能并不关心您的示例中的整数的逻辑and/or。整数不是布尔值,因此不应提供逻辑运算符。 bool 和 integer 是同一件事是 c 的历史属性之一,新语言不需要镜像。而ints 上的位运算符与逻辑运算符的区别仅存在于 c 中,因为 c 无法区分布尔值和整数。这种区分在区分这些类型的语言中是不必要的。

在 C# 中调用 & 按位运算会产生误导。 &&& 的本质不是逻辑与按位 and。这不是由您使用的运算符决定的,而是由您使用的类型决定的。在逻辑类型(boolbool?DBBool)上,两个运算符都是逻辑的,而在整数类型上,& 是按位的,&& 没有意义,因为你不能在整数上短路. && vs &的本质是第一个短路,第二个没有。

对于完全定义运算符的情况,这与 c 解释一致。而且由于&& 没有在整数上定义,因为这对于&& 的C# 解释没有意义,因此您不存在如何对整数评估&& 的问题。

【讨论】:

  • 优秀的答案。我再一次确切地知道他们为什么这样做。这是完全有道理的。虽然,我确实想添加null && false == false让我觉得奇怪。以及null || false == null。我会交换它们 (N&&F=N, N||F=F)
  • @acid 同时输入truefalse 而不是null。在&& 示例中,这两种情况都为假。因此,如果错误,您可以放心地说出结果。在|| 示例中,您将获得一次true 和一次false。所以结果是未定义的,因此是null。所以这样说是有道理的。
  • 做你真正的&&假的事情,它实际上很合乎逻辑。好的例子。我仍然需要一个示例来说明为什么有人会使用此功能。现在我正在设计一种语言,我完全禁止它。 -编辑-嗯。我明白为什么 null||true 是真的。但我不确定为什么 null||false = null。在我的示例中,我输入了 true>false>null,但在 C# 中,它的 true>null>false。以一种说话的方式
  • true||false==truefalse||false==false 所以你不知道unknown||false 的结果是什么。所以你需要使用null,它表示一个未知的结果。您可能想查看具有相似属性的 Nullable<T> 上的提升运算符。这个想法是使用未知值(由null 表示),就像使用正常值一样。至少它允许我们以短路的方式重载&&。与 C++ 不同,其中 && 会短路内置类型,但不会短路用户定义的类型。
  • 无论如何我将如何使用此代码?你能给我一个例子,其中 null&&false==false 是可取的吗?还是 null||false=null 可取?我检查了我的语言,现在如果您执行 null && 任何操作,您将得到一个 null 异常。我实际上从来不需要 null && 或 ||在代码中,我想考虑不抛出空异常。我可能在 30 分钟前写了这段代码,它说我不能做 null && 或 ||一点也不。如何在 C# 中使用 null && boolval 功能而不会出现编译错误?甚至布尔? v=val; v&&false 不起作用。 pastie.org/1636054
【解决方案3】:

C# 比 C++ 更安全。

首先 & 被重载,有两个版本一个是按位与运算,它对两个整数类型(例如 int、long)进行运算,并返回第一个参数中的每个位与第二个参数中的相应位的 AND 的结果.例如 0011 & 1010 == 0010。

第二个重载是逻辑与,它对两个布尔类型 (bool) 进行操作,当且仅当两个参数都为真时,它才返回真。

最后你有 && 这是条件 AND,它再次操作两个布尔类型并返回 true 当且仅当两个参数都为真但它还具有附加的保证,如果第一个参数为真,则不会评估第二个参数.这允许您编写诸如 if(arr != null && arr.Length > 0)... 之类的内容,而不会出现短路行为,这会给您一个空引用异常。

规则 |和 ||相似,|为按位和逻辑 OR 重载,并且 ||是条件 OR。

您可能对 C++ 行为感到困惑的原因是整数类型在 C++ 中可以隐式转换为布尔值,0 为假,其他任何值都为真,因此 5 && 5 在 C++ 中返回真。在 C# 中,整数类型不能隐式转换为布尔值,因此 5 && 5 是类型错误。 && 和 ||然而,在 C++ 中也会发生短路,所以你不应该对 C# 中的相同感到惊讶。

【讨论】:

    【解决方案4】:

    这些运算符如果翻译成VB.Net就更容易理解了,如下:

    && = AndAlso: IF foo IsNot Nothing AndAlso foo.bar=1 then ...

    || = OrElse: If foo Is Nothing OrElse foo.bar=0 then ......

    这样,当您用英文阅读它们时,您就会真正了解它们想要达到的目标。

    【讨论】:

    • 这个帮助,但我还是不明白。假设 foo 是 int 类,而 i am ANDing 的值是 1 和 2。它是如何工作的?另外,我仍然不知道为什么在 && 运算符中使用 &。在 C && 中表示左侧和右侧都必须为真。它与 C 中的逻辑 & 无关。
    • 不知道为什么这些答案会得到 -ve 票 - 似乎有点苛刻!你是什​​么意思 ANDing 1 和 2?
    • 问题的作者只是无法清楚地询问并降低所有试图帮助但无法理解他的人的声誉......
    【解决方案5】:

    这里可能被忽略的部分问题是为什么 C# 不自动将整数转换为布尔值?

    自动将整数转换为布尔值(使用 C/C++ 的规则)允许意外分配而不是比较两个值。 C# 语言设计者可能想避免这种情况...

    int a, b;
    if(a == b)
        { /* They are equal, so execute this code... */ }
    
    if(a = b)
        { /* Were they actually equal? Dunno, but they are now... */ }
    

    while(a = b)
        { /* Eternal loop */ }
    

    【讨论】:

      【解决方案6】:

      如果您希望双方都被评估,您需要使用“标准”& 和 |运营商。通常你确实想要 && 和 ||运营商虽然是为了效率

      【讨论】:

      【解决方案7】:

      如果x == false,则x && y 将始终为false -> 无需查看y 的值。如果x == true,那么x & y 就会发生。这为您提供优化的逻辑操作。

      对于int,它将类似于:T.false(x == true) ? x : T.&(x == true, y == true)

      【讨论】:

      • 我的问题令人困惑。尝试再次阅读或阅读我在其他两个答案中所做的 cmets。我不是在问逻辑,而是为什么运营商的工作很奇怪
      • 它们的工作方式很奇怪,因为您试图以奇怪的方式使用它们。 Ints 不是真/假值。因此,您不能将 C# 的逻辑用于 C++ 的整数。并阅读我的答案的编辑。
      猜你喜欢
      • 2012-03-21
      • 1970-01-01
      • 2015-08-20
      • 2017-07-14
      • 1970-01-01
      • 2019-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多