web-dev-qa-db-ja.com

C#7コンパイラエラー-パターンマッチング

何らかの理由で、M1()はコンパイラエラーを引き起こしますが、同じことを行うM2()はエラーを引き起こしません。理由は何ですか?

false ==の使用は、not演算子!の使用と同じである必要があります。

割り当てられていないローカル変数「i」の使用

class Program {
    static void Main(string[] args) {
        int x = 8;

        M1(x);
        M2(x);
    }  // Main()

    public static void M1(Object obj) {
        if (false == (obj is int i))  // Causes ERROR on WriteLine
            return;

        System.Console.WriteLine(i); // Use of unassigned local variable 'i'
    }

    public static void M2(Object obj) {
        if (!(obj is int i))  // OKAY
            return;

        System.Console.WriteLine(i);
    }
} // class Program
28
Tom Baxter

ここでの問題は、コンパイラが「trueの場合に確実に割り当てられる」を処理する方法にあります。 _!_はそれを反転します; _== false_はしません。したがって、コードの場合:

_if (!(obj is int i))
        return;

System.Console.WriteLine(i);
_

コンパイラーは、_obj is int i_がfalseの場合、_!_がそれを反転するため、returnでない場合はintが発生すると推測できます。したがって、iは後続のコードに安全に「リーク」することができます。

ただし、同じルールは_== false_には適用されません。人間のコードリーダーと意味的には同じですが、コンパイラーは_!_と_== false_を非常に異なるものとして扱います。だから:

_if (false == (obj is int i))
_

コンパイラは、iの割り当て状態を知ることができないため、エラーが発生します。

これに関する議論については、 _(x is T y) == false_誤った「割り当てられていないローカル変数の使用」」を参照してください。

話の教訓:C#パターンを使用する場合は、falseとの比較を避け、_!_を使用してください。

[〜#〜]編集[〜#〜]

ここでは、_== false_は特別な場合ではないことに注意してください。 _==_を使用すると、コンパイラーが「trueの場合に確実に割り当てられる」と判断する機能が失われます。たとえば、次のコードはコンパイルされます。

_object x = 1;
if (!(x is bool y))
    return 0;

var z = y;
_

ただし、_== true_を追加すると、次の機能はなくなります。

_object x = 1;
if (!(x is bool y == true))
    return 0;

var z = y; // error: use of an unassigned variable
_

EDIT2

ちなみに、if (expression == false)が読みにくいと感じたために、if (!expression)を使用する人は、---(構文、if !(expression)がC#8 で考慮されます。

20
David Arno

良い発見、これが私が思うことです。これは間違いなく修正できるものですが、私はその理由を見つけようとしていることに注意してください。これは正確な答えではないことに注意してください。ただ言って!

この問題を引き起こすのは_false ==_だけでなく、_== true_によってiがどちらのブランチでも使用できなくなるため、先に進んでこれを作成しました。

_var x = obj is int i;
if(x) Console.WriteLine(i);
_

同じエラーが発生します。 xが真であるかどうかがわかるように、iを初期化する必要がありますよね? xの値をいじり始めない限り!ここでxは定数ではないため、ifステートメントを実行する前にxが常にtrueのままであることを保証することはできません。

ただし、コンパイラはコンパイル時に定数値と式を計算できます。ここで何が起こっているのかわかりませんが、私が思うのは

if((obj is int i) == false)

ここで_==_演算子は、パターンマッチングの結果とifステートメントの評価の間にギャップを置きます。したがってエラーになります。 _!_演算子が正常に機能する理由がわかりません。おそらく、その部分を最適化したのに、これを最適化するのを忘れたのでしょうか。 ;)

これはコンパイラのセマンティック分析フェーズに関連していると思います。その仕事は、コードの意味を検証し、コードの実行方法を決定することです。何か問題がある場合、未定義の動作の可能性がある場合、またはまったく意味のないものがある場合、失敗してあなたはコンパイル時エラーが発生します。続きを読む コンパイラ設計のフェーズ

0
M.kazem Akhgary