C# 中“!=”和“不是”有区别吗?

Tha*_*nos 103 c# syntax if-statement

这是:

if(x != y)
{

}
Run Code Online (Sandbox Code Playgroud)

与此不同:

if (x is not y)
{

}
Run Code Online (Sandbox Code Playgroud)

或者说这两个条件没有区别?

Dai*_*Dai 162

比较表:

操作员 != is not
最初的目的 价值不平等 否定模式匹配
可以执行价值不平等 是的 是的
可以执行否定模式匹配 是的
可以调用implicit左侧操作数上的运算符 是的
可以调用implicit右侧操作数上的运算符 是的 1
是自己的运营商 是的 2
可重载 是的
自从 C#1.0 C#9.0 3
值类型空比较分支省略4 是的 [需要引用] 5
不可能的比较 错误 警告
左操作数 任意表达 任意表达
右操作数 任意表达 仅常量表达式6
句法 <any-expr> != <any-expr> <any-expr> is [not] <const-expr> [or|and <const-expr>]*
和更多

常见示例:

例子 != is not
不为空 x != null x is not null
价值不平等的例子 x != 'a' x is not 'a'
运行时类型(不)匹配 x.GetType() != typeof(Char) x is not Char7
SQLx NOT IN ( 1, 2, 3 ) x != 1 && x != 2 && x != 3 x is not 1 or 2 or 3

直接而具体地回答OP的问题:

if( x != y ) { }
// vs:
if( x is not y ) { }
Run Code Online (Sandbox Code Playgroud)
  • 如果x是整型值类型(例如int/ Int32)并且y是 a const-expression(例如const int y = 123;),则no,没有区别,并且两个语句都会生成相同的 .NET MSIL 字节码(启用和不启用编译器优化):

    在此输入图像描述

  • If y is a type-name (instead of a value name) then there is a difference: the first if statement is invalid and won't compile, and the if( x is not y ) statement is a type pattern match instead of a constant pattern match.


Footnotes:

  1. "Constant Pattern": "When the input value is not an open type, the constant expression is implicitly converted to the type of the matched expression".

  2. x is not null is more analogous to !(x == null) than x != null.

  3. C# 7.0 introduced some limited forms of constant-pattern matching, which was further expanded by C# 8.0, but it wasn't until C# 9.0 that the not negation operator (or is it a modifier?) was added.

  4. Given a non-constrained generic method, like so:

    void Foo<T>( T x )
    {
        if( x == null ) { DoSomething(); }
    
        DoSomethingElse();
    }
    
    Run Code Online (Sandbox Code Playgroud)

    ...when the JIT instantiates the above generic method (i.e.: monomorphization) when T is a value-type (struct) then the entire if( x == null ) { DoSomething(); } statement (and its block contents) will be removed by the JIT compiler ("elision"), this is because a value-tupe can never be equal to null. While you'd expect that to be handled by any optimizing compiler, I understand that the .NET JIT has specially hardcoded rules for that particular scenario.

    • Curiously in earlier versions of C# (e.g. 7.0) the elision rule only applied to the == and != operators, but not the is operator, so while if( x == null ) { DoSomething(); } would be elided, the statement if( x is null ) { DoSometing(); } would not, and in fact you would get a compiler error unless T was constrained to where T : class. Since C# 8.0 this seems to now be allowed for unconstrained generic types.
  5. Surprisingly I couldn't find an authoritative source on this (as the published C# specs are now significantly outdated; and I don't want to go through the csc source-code to find out either).

    • If neither the C# compiler or JIT do apply impossible-branch-elision in generic code with Constant-pattern expressions then I think it might simply because it's too hard to do at-present.
  6. Note that a constant-expression does not mean a literal-expression: you can use named const values, enum members, and so on, even non-trivial raw expressions provided all sub-expressions are also constant-expressions.

    • I'm curious if there's any cases where static readonly fields could be used though.
  7. 请注意,在 的情况下typeof(X) != y.GetType(),此表达式将返回truewhen Xis 派生自y的类型(因为它们是不同的类型),但x is not Y实际上是false因为x is Y(因为x是 的子类的实例Y)。使用时Type最好做类似typeof(X).IsSubclassOf(y.GetType()), 甚至更宽松的事情y.GetType().IsAssignableFrom(typeof(X))

    • 尽管在这种情况下,asChar是一个结构体,因此不能参与类型层次结构,所以这样做!x.IsSubclassOf(typeof(Char))是愚蠢的。

  • 第 8 行中的“elison”一词是什么意思? (3认同)
  • 感谢@cg909的澄清,这绝对是一个小众术语,我用 https://ericlippert.com/2013/01/24/ Five-dollar-words-for-programmers-elision/ 交换了 wiki 链接 (2认同)

Dav*_*lor 15

与优秀接受答案中列出的另一个区别是(自 C# 7.0 起),is两个 NaN 值之间是一个匹配的模式,因为x.Equals(y)truex都是yNaN 时,并且 NaN 值没有整数类型。因此,is not在两个 NaN 值之间返回模式不匹配。

但是,C# 遵循 IEEE 浮点和 C,指定!=两个 NaN 值之间的比较为,true它们==之间的比较为false。这主要是因为1980 年的 Intel 8087 浮点协处理器没有其他方法来测试 NaN。

  • @NeilMeyer “爱因斯坦认为,必须对自然进行简化的解释,因为上帝不是反复无常或任意的。没有这样的信念可以让软件工程师感到安慰。” ——弗雷德·布鲁克斯 (9认同)