1. ホーム
  2. c#

[解決済み] C#の"!="と "is not "は違うのですか?

2023-03-05 08:05:16

質問

これは何ですか?

if(x != y)
{

}

とは異なります。

if (x is not y)
{

}

それとも、2つの条件に違いはないのでしょうか?

どのように解決するのですか?

比較表です。

<テーブル 演算子 != is not 本来の目的 値の不等号 否定的な パターンマッチ 値の不等式を行うことができる 可能 はい 否定的なパターンマッチを行うことができる いいえ はい 呼び出すことができます implicit 演算子を使用することができます。 はい いいえ 呼び出すことができます implicit 演算子を使用することができます。 はい はい 1 自身の演算子である はい いいえ 2 オーバーロード可能 はい いいえ より C# 1.0 C# 9.0 3 値型ヌル比較ブランチ エリジョン 4 はい いいえ <サブ [要出典] (Citation needed) 5 不可能な比較 エラー 警告 左オペランド 任意の式 任意の表現 右オペランド 任意の式 定数式のみ 6 構文 <any-expr> != <any-expr> <any-expr> is [not] <const-expr> [or|and <const-expr>]*

その他

よくある例です。

<テーブル 例 != is not nullではない x != null x is not null 値の不等号の例 x != 'a' x is not 'a' ランタイムタイプの(誤)一致 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 ) と yconst-expression (である(例えば const int y = 123; ) なら いいえ の場合、違いはなく、両方のステートメントで同じ .NET MSIL バイトコードが生成されます (コンパイラの最適化を有効にしている場合と無効にしている場合の両方)。

  • もし y が(値名ではなく)型名である場合、そこに という違いがあります。 if ステートメントは無効でコンパイルできません。 if( x is not y ) ステートメントは 型パターン の代わりにマッチします。 定数パターン にマッチします。


脚注です。

  1. "定型パターン" : "入力値がオープン型でない場合、定数式はマッチした式の型に暗黙的に変換されます" 。

  2. x is not null は、より類推しやすいように !(x == null) よりも x != null .

  3. C# 7.0 では、いくつかの限定された形式の constant-pattern マッチングが導入され、C# 8.0ではさらに拡張されましたが、C# 9.0になってから not という否定演算子(あるいは修飾子)が追加されたのはC# 9.0です。

  4. のように、非制約のジェネリックメソッドが与えられる。

    void Foo<T>( T x )
    {
        if( x == null ) { DoSomething(); }
    
        DoSomethingElse();
    }
    
    

    ...JITが上記のジェネリックメソッドをインスタンス化するとき(すなわち。 単形化 ) の場合 T が値型( struct ) の場合、全体の if( x == null ) { DoSomething(); } ステートメント ( とそのブロックの内容 ) はJITコンパイラによって削除されます ("elision")。これは、値tupeは決して null . これは、最適化コンパイラーによって処理されることを期待しますが、.NET JIT はこの特定のシナリオのために特別にハードコードされたルールを持っていると私は理解しています。

    • 不思議なことに、C# の以前のバージョン (7.0 など) では、エリジョン ルールは ==!= 演算子ではなく is 演算子ではありませんので if( x == null ) { DoSomething(); } は消去されますが、ステートメント if( x is null ) { DoSometing(); } ではなく でない限り、コンパイラエラーが発生します。 T に拘束されない限り、コンパイラエラーが発生します。 where T : class . C# 8.0 からは、制約のない一般的な型に対して許可されるようになったようです。
  5. 驚いたことに、これに関する権威あるソースは見つかりませんでした (公開されている C# 仕様は現在ではかなり古くなっているためです。 csc のソース コードを調べてみたいとは思いません)。

    • C# コンパイラと JIT のどちらも不可能分岐を適用しない場合は 定数パターン 式がある場合、私は を考える は、単に現状では難しいからかもしれません。
  6. なお 定数式 を意味するものではありません。 リテラル式 を意味するものではありません。 const の値を使うことができます。 enum メンバなど、すべての部分式が同じであれば、自明でない生の式でも 定数式 .

    • というケースがあるのか気になるところです。 static readonly フィールドが使えるかどうかが気になるところですが。
  7. の場合は typeof(X) != y.GetType() の場合、この式は true とすると X から派生したものです。 y の型から派生したものである(両者は異なる型であるため)、しかし 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)) を使うのは馬鹿馬鹿しいだけです。