演習 - コード ブロックと変数のスコープ

完了

コード ブロックは、実行パスを定義する 1 つ以上の C# ステートメントです。 コード ブロックの外側にあるステートメントは、実行時にコードのブロックがいつ実行されるか、実行されるかどうか、実行される頻度に影響を与えます。 コード ブロックの境界は、通常、波線の中かっこ {} によって定義されます。

コード ブロックは、実行パスへの影響に加えて、変数のスコープにも影響を与える可能性があります。 この演習で調べるコード サンプルは、コード ブロックと変数スコープの関係を理解するのに役立ちます。

コード ブロックは変数宣言のスコープに影響を与える

変数 ''スコープ'' は、アプリケーション内の他のコードに対する変数の可視性を指します。 ローカル スコープの変数は、その変数が定義されているコード ブロック内でのみアクセスできます。 コード ブロックの外部にある変数にアクセスしようとすると、コンパイラ エラーが発生します。

このユニットの残りの部分では、コード ブロックと変数スコープの関係について調べます。

コーディング環境を準備する

このモジュールには、デモ コードをビルドして実行するプロセスをガイドする実践的なアクティビティが含まれています。 これらのアクティビティを完了するために、開発環境として Visual Studio Code を使用することをお勧めします。 これらのアクティビティに Visual Studio Code を使用すると、世界中のプロフェッショナルが使用する開発環境でコードの記述と実行をより快適に行うことができます。

  1. Visual Studio Code を開きます。

    Visual Studio Code は、Windows の [スタート] メニュー (別の OS の場合は同等のリソース) を使用して開くことができます。

  2. Visual Studio Code の [ファイル] メニューで、[フォルダーを開く] を選択します。

  3. [フォルダーを開く] ダイアログで、Windows のデスクトップ フォルダーに移動します。

    コード プロジェクトを保持するフォルダーの場所が別にある場合は、代わりにそのフォルダーの場所を使用できます。 このトレーニングでは、見つけやすく覚えやすい場所を用意することが重要です。

  4. [フォルダーを開く] ダイアログで、[フォルダーの選択] を選びます。

    作成者を信頼するかどうかを確認するセキュリティ ダイアログが表示された場合は、[はい] を選択します。

  5. Visual Studio Code の [ターミナル] メニューで、[新しいターミナル] を選択します。

    [ターミナル] パネルのコマンド プロンプトに、現在のフォルダーのフォルダー パスが表示されることを確認します。 次に例を示します。

    C:\Users\someuser\Desktop>
    

    Note

    サンドボックスやホスト環境ではなく、自分の PC で作業しており、この C# シリーズの他の Microsoft Learn モジュールを完了している場合は、コード サンプル用のプロジェクト フォルダーが既に作成されている可能性があります。 その場合は、次の手順 (TestProject フォルダーにコンソール アプリを作成するために使用される) をスキップできます。

  6. ターミナルのコマンド プロンプトで、指定したフォルダーに新しいコンソール アプリケーションを作成するには、「dotnet new console -o ./CsharpProjects/TestProject」と入力し、Enter キーを押します。

    この .NET CLI コマンドでは、.NET プログラム テンプレートを使用して、指定したフォルダーの場所に新しい C# コンソール アプリケーション プロジェクトを作成します。 このコマンドでは、CsharpProjects および TestProject フォルダーが自動的に作成され、.csproj ファイルの名前として TestProject が使用されます。

  7. [エクスプローラー] パネルで、CsharpProjects フォルダーを展開します。

    [TestProject] フォルダーと、Program.cs という名前の C# プログラム ファイルと、TestProject.csproj という名前の C# プロジェクト ファイルの 2 つが表示されるはずです。

  8. [エクスプローラー] パネルの [エディター] パネルにコード ファイルを表示するには、[Program.cs] を選択します。

  9. 既存のコード行を削除します。

    この C# コンソール プロジェクトを使用して、このモジュール中のコード サンプルを作成、ビルド、および実行します。

  10. [ターミナル] パネルを閉じます。

コード ブロックの内側で変数を作成する

まず、コード ブロック内で変数が初期化されたときのケースを確認します。

  1. Visual Studio Code が開いていて、[エディター] パネルに Program.cs が表示されていることを確かめます。

    Note

    Program.cs は空になっているはずです。 そうでない場合は、すべてのコード行を選択して削除します。

  2. Visual Studio Code エディターに次のコードを入力します。

    bool flag = true;
    if (flag)
    {
        int value = 10;
        Console.WriteLine($"Inside the code block: {value}");
    }
    
  3. Visual Studio Code の [ファイル] メニューで、[保存] を選択します。

    コードをビルドまたは実行する前に、Program.cs ファイルを保存する必要があります。

  4. [エクスプローラー] パネルで、TestProject フォルダーの場所にあるターミナルを開くには、TestProject を右クリックし、[統合ターミナルで開く] を選択します。

    [ターミナル] パネルが開きます。 ターミナルには、そのターミナルが TestProject フォルダーの場所で開いていることを示すコマンド プロンプトが含まれているはずです。

  5. [ターミナル] のコマンド プロンプトで、コードを実行するには「dotnet run」と入力し、Enter キーを押します。

    Note

    "実行するプロジェクトが見つかりませんでした" というメッセージが表示された場合は、ターミナルのコマンド プロンプトに、予期されている TestProject フォルダーの場所が表示されていることを確かめます。 例: C:\Users\someuser\Desktop\csharpprojects\TestProject>

    次の出力が表示されます。

    Inside the code block: 10
    

これは予想される出力です。 しかし、if ステートメントのコード ブロックの外側の変数 value にアクセスしたい場合はどうすればよいでしょうか?

変数が宣言されているコード ブロックの外側から変数へのアクセスを試みる

  1. Visual Studio Code エディターで、if ステートメントのコード ブロックの下に新しいコード行を作成します。

  2. 作成した空のコード行に、次のコード行を追加します。

    Console.WriteLine($"Outside the code block: {value}");
    
  3. 更新したコードが次のようになっていることを確認します。

    bool flag = true;
    if (flag)
    {
        int value = 10;
        Console.WriteLine($"Inside the code block: {value}");
    }
    Console.WriteLine($"Outside the code block: {value}");
    
  4. コード ファイルを保存してから、Visual Studio Code を使ってコードを実行します。

    [ターミナル] のコマンド プロンプトから「dotnet run」と入力して、コードを実行します。

  5. アプリケーションを実行しようとすると、次のコンパイル エラーが発生することに注目してください。

    Program.cs(7,46): error CS0103: The name 'value' does not exist in the current context
    

メッセージの Program.cs(7,46) という部分は、エラーが Program.cs ファイルの 7 行目の 46 文字目に関連していることを示しています。

このエラーが発生する原因は、コード ブロック内で宣言された変数にアクセスできる (変数が見える) のは、そのコード ブロック内だけであるためです。 変数が宣言されているコード ブロックの外部からは変数にアクセスできないため、コードの 7 行目からは value にアクセスできません。

メソッドのコード ブロック内で宣言されている変数は、"ローカル変数" と呼ばれます。 変数スコープについて説明している記事を参照した際に、"ローカル変数" という用語が使用されているのを見たことがあるのではないでしょうか。

変数宣言をコード ブロックの上に移動する

コード ブロックの内側と外側の両方で変数にアクセスするには、コード ブロックの外側のコードが変数を "見れる" ように、コード ブロックの前 (上) で変数を宣言する必要があります。

  1. Visual Studio Code エディターで次のようにコードを更新します。

    bool flag = true;
    int value;
    
    if (flag)
    {
        Console.WriteLine($"Inside the code block: {value}");
    }
    
    value = 10;
    Console.WriteLine($"Outside the code block: {value}");
    
  2. 少し時間を取って更新内容を確認します。

  3. valueif コード ブロックの外部で宣言されるようになった (ただし、初期化はされていない) ことに注目してください。

  4. Visual Studio Code を使用して更新内容を保存してから、コードを実行します。

  5. コンパイル エラーが引き続き発生していることに注目してください。

    今度は、アプリケーションを実行しようとすると、次のコンパイル エラーが発生します。

    Program.cs(6,49): error CS0165: Use of unassigned local variable 'value'
    

    エラーはコード ブロック内の 6 行目に関連するもので、原因は value が初期化されていない (値が割り当てられていない) ことです。 コード行 value = 10;if ステートメントのコード ブロックの上にあれば、アプリケーションは正しくコンパイルされ、何も問題は起きないはずでした。 しかし、value は初期化されていないため、コード ブロック内からアクセスできません。

    変数にアクセスしようとする前に変数が初期化されるようにすることで、この問題に対処できます。

変数宣言の一部として変数を初期化する

  1. 変数宣言の一部として value を初期化するには、次のようにコードを更新します。

    bool flag = true;
    int value = 0;
    
    if (flag)
    {
        Console.WriteLine($"Inside the code block: {value}");
    }
    
    value = 10;
    Console.WriteLine($"Outside the code block: {value}");
    

    このコードは、変数宣言の一部として value を初期化することで、コンパイル エラーの "割り当てられていないローカル変数" に対処します。

  2. Visual Studio Code を使ってコードを保存して実行します。

  3. アプリケーションを実行すると、今度は次のような出力が表示されることに注目してください。

    Inside the code block: 0
    Outside the code block: 10
    

コンパイラによるコードの解釈を調べる

ランタイム エラーを回避するために、C# コンパイラは Visual Studio Code エディタ内、およびビルド プロセス中にコードを分析します。 しかし、コンパイラは常に開発者と同じようにコードを解釈するわけではありません。

同じ目的を果たすように見える以下の 2 つのコード サンプルを考えてみましょう。

// Code sample 1
bool flag = true;
int value;

if (flag)
{
    value = 10;
    Console.WriteLine($"Inside the code block: {value}");
}

Console.WriteLine($"Outside the code block: {value}");
// Code sample 2
int value;

if (true)
{
    value = 10;
    Console.WriteLine($"Inside the code block: {value}");
}

Console.WriteLine($"Outside the code block: {value}");

これら 2 つのサンプルは常に同じ結果を生成するはずだと思えるかもしれませんが、C# コンパイラによるこれら 2 つのコード サンプルの解釈は異なります。

最初のコード サンプルでは、コンパイラは flag を、true または false のどちらかの値を割り当てることができるブール値変数と解釈します。 コンパイラは、flagfalse である場合、2 番目の Console.WriteLine() が実行される時点で value が初期化されていないことになると結論付けます。 本質的に、コンパイラは以下の 2 つのコード実行パスがあり得ると考えます。

// path when flag = true
int value;
value = 10;
Console.WriteLine($"Inside the code block: {value}");
Console.WriteLine($"Outside the code block: {value}");

かつ

// path when flag = false
int value;
Console.WriteLine($"Outside the code block: {value}");

コンパイラは (コード サンプル 1 に対しては) 2 番目のパスがあり得ると考えるため、ビルド プロセス中にエラー メッセージを生成します。 さらに、Visual Studio Code のコード エディターは、(コード ブロックの下の) value の下に赤い波線を表示することで、この問題を開発者に警告します。

2 番目のコード サンプルに関しては、コンパイラは if ステートメントのコード ブロックの内容が常に実行されることになる (true は常に true である) と結論付けます。 コンパイラは、2 番目のコード サンプルは次のような 1 つの実行パスを持つと解釈するため、ビルド エラーを生成しません。

int value;
value = 10;
Console.WriteLine($"Inside the code block: {value}");
Console.WriteLine($"Outside the code block: {value}");

まとめ

コード ブロックについて覚えておく必要がある重要な点を次に示します。

  • コード ブロックの内側で変数を宣言すると、変数の可視性はそのコード ブロックに対してローカルになり、コード ブロックの外側からはその変数にアクセスできなくなります。
  • 変数がコード ブロックの内側と外側の両方で見えるようにするには、コード ブロックの前 (コード ブロックの外かつ上) で変数を宣言する必要があります。
  • コードが (すべての潜在的なコード実行パスで) 変数へのアクセスを試みる前に、変数が初期化されるように注意します。

知識を確認

1.

開発者は、if ステートメントのコード ブロックを含むコードを記述しています。 1 つの整数変数を、コード ブロックの上 (外側) の 5 の値に初期化します。 コード ブロック内の最初の行で、2 番目の整数変数を 6 の値に初期化します。 コード ブロックのこのブール式は、最初の整数変数の値が 0 より大きい場合は、true と評価されます。 コード ブロック内の 2 行目では、2 つの値の合計を最初の変数に割り当てます。 コード ブロックの後の 1 行目で、1 番目の整数の値を表示するコードを記述します。 1 番目の整数の表示に使われるコード ステートメントが実行されると、結果はどのようになりますか?