为啥 C# 中的 1 && 2 为假?

Posted

技术标签:

【中文标题】为啥 C# 中的 1 && 2 为假?【英文标题】:Why is 1 && 2 in C# false?为什么 C# 中的 1 && 2 为假? 【发布时间】:2011-07-09 09:27:15 【问题描述】:

I got frustated with my other question。所以我写了这个例子。

In C the below is true. See demo

int main()

printf("%d", 1 && 2);
return 0;

输出:

1

在 C# 中。这是错误的。为什么这是假的? 我也不明白为什么我需要在这个例子中创建 bool 运算符,但不是我的另一个问题中的那个,但没关系。为什么下面是假的?这对我来说毫无意义。

顺便说一句,使以下错误的逻辑描述为here

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1

    class Program
    
        static void Main(string[] args)
        
            MyInt a=1, b=2;
            bool res=a && b;
            Console.WriteLine("result is 0", res);
        

        class MyInt
        
            public int val;
            public static bool operator true(MyInt t)  return t.val != 0; 
            public static bool operator false(MyInt t)  return t.val == 0; 
            public static MyInt operator &(MyInt l, MyInt r)  return l.val & r.val; 
            public static MyInt operator |(MyInt l, MyInt r)  return l.val | r.val; 
            public static implicit operator MyInt(int v)  return new MyInt()  val = v ; 
            public static implicit operator bool(MyInt t)  return t.val != 0; 
        
    

【问题讨论】:

如果你想用 C 编写代码,就用 C 编写代码。如果你想用 C++ 编写代码,就用 C++ 编写代码。如果你想在 C# 中编写 C# 代码。但是你不能假设这些语言是可以互换的。如果您的代码按照您正在编写的语言的规则而不是按照其他语言的规则进行编码,您将获得最大的成功。 通用约定应该总是胜过其他所有方面 - 如果 1 始终为真,而 0 始终为假,则应该批评一种以不同方式做事的语言。我们这些可怜的人只记得这么多,而且我们会犯错误,所以改变惯例只会增加错误的可能性。 @gbjbaanb:确切地说,如果它会改变,至少告诉我们它背后的原因,这样我们就可以利用它改变的原因。这就是我想问的(三遍。几乎没有人知道)。这(原因)就是为什么我喜欢 CodeInChaos 在另一个问题中的回答 ***.com/questions/5203498/… @gbjbaanb: 如果 & 和 | 对于上面的 MyInt 类,0 保持为假,1 保持为真正如我在下面指定的那样,运算符已正确实现。该语言并没有“以不同的方式做事”,至少不是您似乎暗示的方式。它只使用 & 和 |当操作数不是整数时,作为非短路布尔运算符。 @Eric J.:我阅读了泛型、getter、setter、this[T t],以及显式/隐式转换如何工作,因为它不同于 C++ 运算符 T()。但是,我没有研究 for 循环是如何工作的或 '|' 是如何工作的有效,因为每种语言都有它们并且它们都工作相同。然而,我没想到||到现在为止会有所不同,也不会有所不同。它做得很好,让我相信它是一样的。我不认为您建议我应该阅读每种语言的函数调用如何工作? (但我确实知道命名参数,但自从我开始使用的版本以来这是新的)或者赋值运算符? 【参考方案1】:

我会尽量简化,因为我认为人们过于复杂了。

var x = 1 & 2;
// behind the scenes: 0001 AND 0010 = 0000
Console.Write(x); // 0, as shown above

整数不能在 C# 中用作布尔值。结果:

if (1 && 2) // compile error
var x = 1 && 2; // compile error

没有必要问为什么 Integer 不能在 C# 中用作布尔值,它就是不能。类型系统不允许这样做。如果要实现自己的 Integer 类,他们可以提供从其类型到 bool 的隐式转换,但 int 这样做。重载时您也必须做出选择;你想要按位行为还是逻辑行为。你不能两者兼得。

某些语言允许 0、""、[] 作为 'falsey' 值。 C# 没有。克服它,如果您正在执行布尔逻辑,请使用布尔值。如果所有其他方法都失败,则 int 上的 Convert.ToBoolean 将为所有非零值返回 true

【讨论】:

【参考方案2】:

C 中没有bool。约定是0false!= 0trueif 语句正是这样处理条件表达式的结果。

C++ bool 中引入。但它兼容旧规则,0 被视为falsefalse 被视为0,并且intbool 之间存在隐式转换。

在 C# 中则不同:有boolint,它们不能相互转换。这就是 C# 标准所说的。期间。

因此,当您尝试重新实现 boolint 兼容性时,您犯了一个错误。您使用 && 这是逻辑运算符,但在 C# 中您不能覆盖它,只能使用 &,它是按位实现的。 1 & 2 == 0 == false!在这里!

你甚至不应该重载按位,为了保持兼容性你只需要离开operator truefalse

此代码按预期工作:

class Programx

    static void Main(string[] args)
    
        MyInt a = 1, b = 2;
        bool res = a && b;
        Console.WriteLine("result is 0", res);
    

    class MyInt
    
        public int val;
        public static bool operator true(MyInt t)
        
            return t.val != 0;
        
        public static bool operator false(MyInt t)
        
            return t.val == 0;
        
        public static implicit operator MyInt(int v)
        
            return new MyInt()  val = v ;
        
        public static implicit operator bool(MyInt t)
        
            return t.val != 0;
        
    

结果为真

【讨论】:

我一直认为 int 没有隐式转换为 bool 以避免意外的 if/while/for 问题。如果我写了这个结果是真的 var b1 = Convert.ToBoolean(a.val); var b2 = Convert.ToBoolean(b.val); Console.WriteLine("结果为 0", b1&&b2);.为什么 C# 不做布尔值和 C 做的方式。为什么布尔值和逻辑是这样的? 在 C 中 直到 1999 年才有bool 好的被接受为答案。但是... WTF,现在我不能使用按位与。如果我确实添加了按位与逻辑与中断... WTF。我还是不明白为什么 C# 使用 && 作为短路 &。 即使在今天,处理器也使用这些指令。具有与 int 不同的 bool 的抽象不会消耗任何性能,但会使语言更简洁。就处理器而言,就像指针和整数之间没有区别一样。但是用一种语言将它们分开仍然是有意义的。通常情况下,如果您对某件事过于熟悉,您就会对替代品视而不见,即使替代品更好。不幸的是,这种情况发生在我们所有人身上的频率超出了我们的预期。 您不会在运行时放弃任何周期。并且同一时代的 pascal 编译器也有这个特性【参考方案3】:
public static MyInt operator &(MyInt l, MyInt r)  return l.val & r.val; 

如果我正确阅读了链接的文章, res = a && b 将被“扩展”为:

MyInt.false(a) ? a : MyInt.&(a, b)

MyInt.false(a) 为假,因此计算结果为:

MyInt.&(a, b)

其中“扩展”为:

a.val & b.val

这是 (1 & 2) == 0,因此是 false

【讨论】:

是的,我从一开始就知道为什么我问我的另一个问题。我的问题是它为什么要这样做!?! 哪部分让你很烦? (1&2) == 0? @acidzombie24 为什么不呢?想象一下,你从 Pascal 来到 C/C++,你是从以下开始的:#define Begin #define End 吗?或者你会阅读语言参考并使用新规则? @Mat: bool 1 为真,bool 2 为真,但 1&&2 不是。 @Nick:好吧,如果 && 是合乎逻辑的而不是布尔值,那为什么还要费心把它短路呢?如果它假设它像 C (因为大部分语法是相似的)为什么甚至有 && 或使它不像 C 那样布尔值。如果它假设做一个逻辑和,我不明白它的用途。【参考方案4】:

您对 operator& 和 operator| 的实现错了。这些二元运算符在应用于整数类型以及应用于布尔类型或具有自己的 & 和 | 的类时具有按位含义。运算符,它们具有逻辑 AND 和 OR 语义(是 && 和 || 的非短路表亲)。正确的实现如下所示:

operator &(MyInt l, MyInt r) return l.val != 0 && r.val != 0);
operator |(MyInt l, MyInt r) return l.val != 0 || r.val != 0);

【讨论】:

WTF!?!所以... & 是逻辑的还是短路的逻辑?不是布尔逻辑? (也许我说错了,但我想你知道我的意思吗?) 最重要的是,您根本无法在 C# 中创建一个整数类型,该类型支持使用 & 和 | 对该整数进行按位运算运算符,同时重载 true/false 以提供逻辑真值测试。 @acidzombie24:恐怕我不明白你所说的区别。 & 和 |,当支持作为类上的用户定义运算符时,执行双重职责,同时支持非短路逻辑(即布尔值)& 和 |运算和短路逻辑(即布尔值)&& 和 ||操作。它们不支持按位(即二进制数学)运算。 @acid && 在任何合理的类型上都不是按位短路。您问题的核心是误解 & 在 C# 中表示按位 and。它没有。表示非短路and 你的类型的问题不是&的错误实现,而是truefalse的错误实现。这些运算符不应存在于非逻辑类型上。请参阅我对您的旧问题的回答,了解为什么这些运算符在 C# 中是这样设计的。

以上是关于为啥 C# 中的 1 && 2 为假?的主要内容,如果未能解决你的问题,请参考以下文章

查找中的权限被拒绝:为啥我们需要 2>&1?

为啥 Mutex 被设计为需要 Rust 中的 Arc

为啥 2 && 3 结果为 3 (javascript)? [复制]

为啥许多编程语言中的集合不是真正的集合?

为啥initializer_list中的字符串内容为空?

c#替换文件中的字符串