这是:
if(x != y)
{
}
与此不同:
if (x is not y)
{
}
还是说这两种情况没有任何区别吗?
这是:
if(x != y)
{
}
与此不同:
if (x is not y)
{
}
还是说这两种情况没有任何区别吗?
运算符 | != |
is not |
---|---|---|
原始目的 | 值不相等 | 否定模式匹配 |
可执行值不相等 | 是 | 是 |
可执行否定模式匹配 | 否 | 是 |
可以在左操作数上调用implicit 运算符 |
是 | 否 |
可以在右操作数上调用implicit 运算符 |
是 | 是1 |
自身运算符 | 是 | 否2 |
可重载 | 是 | 否 |
自从 | C# 1.0 | C# 9.03 |
值类型空比较分支省略4 | 是 | 否[需要引用]5 |
不可能的比较 | 错误 | 警告 |
左操作数 | 任何表达式 | 任何表达式 |
右操作数 | 任何表达式 | 仅常量表达式6 |
语法 | <any-expr> != <any-expr> |
<any-expr> is [not] <const-expr> [or|and <const-expr>]* 以及更多 |
例子 | != |
is not |
---|---|---|
非空 | x != null |
x 不是 null |
值不相等的例子 | x != 'a' |
x 不是 'a' |
运行时类型(不)匹配 | x.GetType() != typeof(Char) |
x 不是 Char 类型 7 |
SQL x NOT IN ( 1, 2, 3 ) |
x != 1 && x != 2 && x != 3 |
x 不是 1 或 2 或 3 |
if( x != y ) { }
// vs:
if( x is not y ) { }
x
是整数值类型(例如int
/ Int32
),而y
是一个const-expression
(例如const int y = 123;
),那么不会有区别,两个语句生成的.NET MSIL字节码相同(启用和不启用编译器优化都一样):
如果y
是一个类型名称(而不是值名称),则存在区别:第一个if
语句无效并且不能编译,而if( x is not y )
语句是一个类型模式匹配而不是一个常量模式匹配。
脚注:
"Constant Pattern": "When the input value is not an open type, the constant expression is implicitly converted to the type of the matched expression".
x is not null
is more analogous to !(x == null)
than x != null
.
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.
Given a non-constrained generic method, like so:
void Foo<T>( T x )
{
if( x == null ) { DoSomething(); }
DoSomethingElse();
}
...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.
==
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.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).
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.
static readonly
fields could be used though.Note that in the case of typeof(X) != y.GetType()
, this expression will return true
when X
is derived from y
's type (as they are different types), but x is not Y
is actually false
because x
is Y
(because x
is an instance of a subclass of Y
). When using Type
it's better to do something like typeof(X).IsSubclassOf(y.GetType())
, or the even looser y.GetType().IsAssignableFrom(typeof(X))
.
Char
is a struct and so cannot participate in a type-hierarchy, so doing !x.IsSubclassOf(typeof(Char))
would just be silly.x
是非空的,则 x != null
总是可以优化为 true
。 - cg909is
是一种匹配模式,因为x.Equals(y)
在x
和y
都是NaN时是true
,而且NaN值没有整数类型。因此,两个NaN值之间的is not
返回模式不匹配。!=
比较为true
,它们之间的==
比较为false
。这主要是因为1980年的英特尔8087浮点协处理器没有其他测试NaN的方法。
nul和undefined是变量可能包含的没有值的属性。相等性检查需要实际值才能确定是否相等。毕竟,如果没有人知道Sally和Peter拥有多少苹果,那么他们是否拥有相同数量的苹果的问题是没有意义的。
有时候你想检查一个变量是否有一个没有值的属性。基本的相等性检查是不足够的。这时候is / is not操作符就派上用场了。可以说!= 是一个值检查,而is / is not是一个属性检查。
null
在原则上类似于 NaN,但是在 null
引用上,is
和 ==
之间没有差异。null == null
的计算结果为 true。两个引用类型之间的模式匹配被指定为与 Equals(Object)
一致,并且“对 Equals(Object)
方法的调用等效于对 ReferenceEquals
方法的调用。” 这反过来又被指定为,“如果 objA
是与 objB
相同的实例或者两者都为 null
,则返回 true
。” 因此,null == null
和 null is null
给出相同的结果。 - Davislor!=
以出人意料的方式被重载,否则不会有任何差异。 - Davislorif (expr is Type v)
被创建为显式null
检查的简洁替代方式。因此,微软的编码风格更喜欢使用它而不是v != null
或v is not null
。 - Davislorx = NULL
为UNKNOWN
,这对于所有人,从初学者到专家都是一个重要的陷阱。在SQL中,“IS NULL”只是一个狗戏表演。 - DaiNaN
仅适用于IEEE-754浮点数(而不适用于其他数字类型),而null
本身就是一个值,而不是被概念化为“没有值”的情况,因为在C#中,null
是引用的值,也适用于Nullable<T>
(也不要称其为单子)。 - DaiTLDR: x != 1 && x != 2 && x != 3
等同于 x 不是 1 且不是 2 且不是 3
或者 x 不是 (1 或 2 或 3)
x 不是 1 或 2 或 3
等同于 x != 1 || x == 2 || x == 3
x != 1 && x != 2 && x != 3
和 x is not 1 or 2 or 3
应该是等价的(如果我理解正确的话)。x != 1 && x != 2 && x != 3
等同于 x is not 1 and not 2 and not 3
。
x != 1 && x != 2 && x != 3
等同于 x 不是 (1 或 2 或 3)
using System;
public class Program
{
public static void Main()
{
var x = 3;
if(x is not 1 or 2 or 3){
Console.WriteLine("x is not 1 and is not 2 and is not 3");
}
}
}
output: "x is not 1 and is not 2 and is not 3"
if(x != 1 && x != 2 && x != 3){
Console.WriteLine("x is not 1 and is not 2 and is not 3");
}
else{
Console.WriteLine("x is 1 or 2 or 3");
}
output: "x is 1 or 2 or 3"
or
和and
关键字。详情请见https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/patterns#logical-patterns - StriplingWarrior( x == 1 || x == 2 || x ==3 )
这样简单的情况下,编译器是否能够将其优化为单个评估,然后以与x is 1 or 2 or 3
相同的方式进行比较?我绝对不会怀疑你 - 我只是为了自己的教育而问一下。 - Sprattyx
可能具有副作用,编译器无法知道代码是否打算在每次比较后重新评估表达式。 - castholm