C#中的“!=”和"is not"有区别吗?
Is there a difference between "!=" and "is not" in C#?
这是:
if(x != y)
{
}
与此不同:
if (x is not y)
{
}
或者说这两个条件没有区别?
比较table:
Operator
!=
is not
Original purpose
Value inequality
Negated pattern matching
Can perform value inequality
Yes
Yes
Can perform negated pattern matching
No
Yes
Can invoke implicit
operator on left-hand operand
Yes
No
Can invoke implicit
operator on right-hand operand(s)
Yes
Yes1
Is its own operator
Yes
No2
Overloadable
Yes
No
Since
C# 1.0
C# 9.03
Value-type null-comparison branch elision4
No[Citation needed]5
Impossible comparisons
Error
Warning
Left operand
Any expression
Any expression
Right operand(s)
Any expression
Only constant expressions6
Syntax
<any-expr> != <any-expr>
<any-expr> is [not] <const-expr> [or|and <const-expr>]*
and more
常见例子:
Example
!=
is not
Not null
x != null
x is not null
Value inequality example
x != 'a'
x is not 'a'
Runtime type (mis)match
x.GetType() != typeof(Char)
x is not Char
7
SQL x 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 ) { }
如果x
是整数值类型(例如int
/Int32
)并且y
是const-expression
(例如 const int y = 123;
) 然后 no,没有区别,两个语句都会生成相同的 .NET MSIL 字节码(启用和不启用编译器优化):
如果 y
是类型名称(而不是值名称),那么 是 一个区别:第一个 if
语句无效且无法编译,并且 if( x is not y )
语句是 类型模式 匹配而不是 常量模式 匹配。
脚注:
"Constant Pattern": "当输入值不是开放类型时,将常量表达式隐式转换为匹配表达式的类型"。
x is not null
比 x != null
.
更类似于 !(x == null)
C# 7.0 引入了一些有限形式的 constant-pattern 匹配,C# 8.0 对其进行了进一步扩展,但直到 C# 9.0 才not
添加了否定运算符(或者它是修饰符?)。
给定一个不受约束的泛型方法,像这样:
void Foo<T>( T x )
{
if( x == null ) { DoSomething(); }
DoSomethingElse();
}
...当 JIT 实例化上述泛型方法(即:monomorphization),当 T
是值类型(struct
)时,整个 if( x == null ) { DoSomething(); }
语句( 及其块内容)将被 JIT 编译器(“省略”)删除,这是因为值元组永远不会等于 null
。虽然您希望任何优化编译器都能处理该问题,但我知道 .NET JIT 具有针对该特定场景的特别硬编码规则。
- 奇怪的是,在早期版本的 C#(例如 7.0)中,省略规则仅适用于
==
和 !=
运算符,而不适用于 is
运算符,因此虽然 if( x == null ) { DoSomething(); }
将被省略,语句 if( x is null ) { DoSometing(); }
将 而不是 ,事实上,除非 T
被限制为 where T : class
,否则您将得到一个编译器错误。从 C# 8.0 开始,现在似乎允许不受约束的泛型类型。
令人惊讶的是,我找不到这方面的权威来源(因为已发布的 C# 规范现在已经过时了;而且我不想查看 csc
源代码找出其中一个)。
- 如果 C# 编译器或 JIT 都没有在具有 常量模式 表达式的泛型代码中应用不可能的分支省略,那么我 认为可能只是因为目前做起来太难了。
请注意,常量表达式并不意味着文字表达式:您可以使用命名const
值,enum
成员,等等,即使是非平凡的原始表达式,所有子表达式也是 constant-expressions.
- 我很好奇在某些情况下是否可以使用
static readonly
字段。
请注意,在 typeof(X) != y.GetType()
的情况下,当 X
派生自 y
时,此表达式将 return true
' s 类型(因为它们是不同的类型),但 x is not Y
实际上是 false
因为 x
是 Y
(因为 x
是 Y
的子类的一个实例)。使用 Type
时,最好使用 typeof(X).IsSubclassOf(y.GetType())
或更宽松的 y.GetType().IsAssignableFrom(typeof(X))
.
- 虽然在这种情况下,由于
Char
是一个结构,因此不能参与类型层次结构,所以 !x.IsSubclassOf(typeof(Char))
只会很愚蠢。
与优秀接受的答案中列出的另一个区别是(自 C# 7.0 起),两个 NaN 值之间的 is
是匹配的模式,因为 x.Equals(y)
is true
when both x
and y
are NaN, 和 NaN 值没有整数类型。因此,is not
两个 NaN 值之间 returns 表示模式不匹配。
但是,C# 遵循 IEEE 浮点和 C specifying that a !=
comparison between two NaN values is true
and an ==
comparison between them is false
. This was mainly because the Intel 8087 floating-point co-processor back in 1980 had no other way to test for NaN.
Nan 和 null 是变量可以包含但没有值的属性。相等性检查需要实际值来确定相等性。毕竟谁都不知道莎莉和彼得有多少个苹果,问莎莉和彼得有多少苹果是没有意义的。
有时您想检查一个变量是否有 属性 没有值。基本的相等性检查对此是不够的。那就是当 is / is not 运算符有用的时候。可以说 != 是一个值检查 where is / is not a 属性 check.
这是:
if(x != y)
{
}
与此不同:
if (x is not y)
{
}
或者说这两个条件没有区别?
比较table:
Operator | != |
is not |
---|---|---|
Original purpose | Value inequality | Negated pattern matching |
Can perform value inequality | Yes | Yes |
Can perform negated pattern matching | No | Yes |
Can invoke implicit operator on left-hand operand |
Yes | No |
Can invoke implicit operator on right-hand operand(s) |
Yes | Yes1 |
Is its own operator | Yes | No2 |
Overloadable | Yes | No |
Since | C# 1.0 | C# 9.03 |
Value-type null-comparison branch elision4 | No[Citation needed]5 | |
Impossible comparisons | Error | Warning |
Left operand | Any expression | Any expression |
Right operand(s) | Any expression | Only constant expressions6 |
Syntax | <any-expr> != <any-expr> |
<any-expr> is [not] <const-expr> [or|and <const-expr>]* and more |
常见例子:
Example | != |
is not |
---|---|---|
Not null | x != null |
x is not null |
Value inequality example | x != 'a' |
x is not 'a' |
Runtime type (mis)match | x.GetType() != typeof(Char) |
x is not Char 7 |
SQL x 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 ) { }
如果
x
是整数值类型(例如int
/Int32
)并且y
是const-expression
(例如const int y = 123;
) 然后 no,没有区别,两个语句都会生成相同的 .NET MSIL 字节码(启用和不启用编译器优化):如果
y
是类型名称(而不是值名称),那么 是 一个区别:第一个if
语句无效且无法编译,并且if( x is not y )
语句是 类型模式 匹配而不是 常量模式 匹配。
脚注:
"Constant Pattern": "当输入值不是开放类型时,将常量表达式隐式转换为匹配表达式的类型"。
更类似于x is not null
比x != null
.!(x == null)
C# 7.0 引入了一些有限形式的 constant-pattern 匹配,C# 8.0 对其进行了进一步扩展,但直到 C# 9.0 才
not
添加了否定运算符(或者它是修饰符?)。给定一个不受约束的泛型方法,像这样:
void Foo<T>( T x ) { if( x == null ) { DoSomething(); } DoSomethingElse(); }
...当 JIT 实例化上述泛型方法(即:monomorphization),当
T
是值类型(struct
)时,整个if( x == null ) { DoSomething(); }
语句( 及其块内容)将被 JIT 编译器(“省略”)删除,这是因为值元组永远不会等于null
。虽然您希望任何优化编译器都能处理该问题,但我知道 .NET JIT 具有针对该特定场景的特别硬编码规则。- 奇怪的是,在早期版本的 C#(例如 7.0)中,省略规则仅适用于
==
和!=
运算符,而不适用于is
运算符,因此虽然if( x == null ) { DoSomething(); }
将被省略,语句if( x is null ) { DoSometing(); }
将 而不是 ,事实上,除非T
被限制为where T : class
,否则您将得到一个编译器错误。从 C# 8.0 开始,现在似乎允许不受约束的泛型类型。
- 奇怪的是,在早期版本的 C#(例如 7.0)中,省略规则仅适用于
令人惊讶的是,我找不到这方面的权威来源(因为已发布的 C# 规范现在已经过时了;而且我不想查看
csc
源代码找出其中一个)。- 如果 C# 编译器或 JIT 都没有在具有 常量模式 表达式的泛型代码中应用不可能的分支省略,那么我 认为可能只是因为目前做起来太难了。
请注意,常量表达式并不意味着文字表达式:您可以使用命名
const
值,enum
成员,等等,即使是非平凡的原始表达式,所有子表达式也是 constant-expressions.- 我很好奇在某些情况下是否可以使用
static readonly
字段。
- 我很好奇在某些情况下是否可以使用
请注意,在
typeof(X) != y.GetType()
的情况下,当X
派生自y
时,此表达式将 returntrue
' s 类型(因为它们是不同的类型),但x is not Y
实际上是false
因为x
是Y
(因为x
是Y
的子类的一个实例)。使用Type
时,最好使用typeof(X).IsSubclassOf(y.GetType())
或更宽松的y.GetType().IsAssignableFrom(typeof(X))
.- 虽然在这种情况下,由于
Char
是一个结构,因此不能参与类型层次结构,所以!x.IsSubclassOf(typeof(Char))
只会很愚蠢。
- 虽然在这种情况下,由于
与优秀接受的答案中列出的另一个区别是(自 C# 7.0 起),两个 NaN 值之间的 is
是匹配的模式,因为 x.Equals(y)
is true
when both x
and y
are NaN, 和 NaN 值没有整数类型。因此,is not
两个 NaN 值之间 returns 表示模式不匹配。
但是,C# 遵循 IEEE 浮点和 C specifying that a !=
comparison between two NaN values is true
and an ==
comparison between them is false
. This was mainly because the Intel 8087 floating-point co-processor back in 1980 had no other way to test for NaN.
Nan 和 null 是变量可以包含但没有值的属性。相等性检查需要实际值来确定相等性。毕竟谁都不知道莎莉和彼得有多少个苹果,问莎莉和彼得有多少苹果是没有意义的。
有时您想检查一个变量是否有 属性 没有值。基本的相等性检查对此是不够的。那就是当 is / is not 运算符有用的时候。可以说 != 是一个值检查 where is / is not a 属性 check.