演習 - 値と参照型のパラメーターを使用する
C# では、変数は、値型と参照型の 2 つの主な型に分類できます。 これらの型は、変数が値を格納する方法を記述します。
int、bool、float、double、charなどの値型には、値が直接含まれます。
string、array、オブジェクト (Random のインスタンスなど) などの参照型は、値を直接格納しません。 代わりに、参照型は、その値が格納されているアドレスを格納します。
値渡しおよび参照渡しパラメーター
引数がメソッドに渡されると、 値 型変数の値がメソッドにコピーされます。 各変数には値の独自のコピーがあるため、元の変数は変更されません。
参照型では、値のアドレスがメソッドに渡されます。 メソッドに指定された変数は、そのアドレスの値を参照するため、その変数に対する操作は、他の変数によって参照される値に影響します。
注
stringは参照型ですが、不変であることを忘れないでください。 つまり、値が割り当てられたら、変更することはできません。 C# では、メソッドと演算子を使用して文字列を変更する場合、返される結果は実際には新しい文字列オブジェクトになります。
この演習では、参照型引数と値型引数をメソッドに渡す方法の詳細について説明します。
値渡しをテストする
Visual Studio Code エディターで、前の演習の既存のコードを削除します。
Visual Studio Code エディターに次のコードを入力します。
int a = 3; int b = 4; int c = 0; Multiply(a, b, c); Console.WriteLine($"global statement: {a} x {b} = {c}"); void Multiply(int a, int b, int c) { c = a * b; Console.WriteLine($"inside Multiply method: {a} x {b} = {c}"); }変数
a、b、およびcは、Multiplyメソッドに渡されます。 変数の値はメソッドの実行中に出力され、メソッドの完了後に再度出力されます。整数は値型であり、メソッドに渡されたときに値がコピーされます。
cの出力は何になると思いますか?コードを保存して実行し、次の出力を確認します。
inside Multiply method: 3 x 4 = 12 global statement: 3 x 4 = 0cの値は、Multiplyメソッド内でのみ変更されることに注意してください。 メソッドの外部では、cは元の値を保持します。
参照渡しをテストする
Visual Studio Code エディターから前のコードを削除します。
Visual Studio Code エディターに次のコードを入力します。
int[] array = {1, 2, 3, 4, 5}; PrintArray(array); Clear(array); PrintArray(array); void PrintArray(int[] array) { foreach (int a in array) { Console.Write($"{a} "); } Console.WriteLine(); } void Clear(int[] array) { for (int i = 0; i < array.Length; i++) { array[i] = 0; } }コードは、いくつかの整数値を格納するために初期化
arrayで始まります。 値は、PrintArrayメソッドを使用して表示されます。Clearメソッドが配列に対して呼び出され、配列が再度出力されます。配列は参照型です。 参照型は、その値のアドレスをメモリに格納します。 出力は何になると思いますか?
コードを保存して実行し、次の出力を確認します。
1 2 3 4 5 0 0 0 0 0配列は、
Clearメソッドスコープの外部で変更されたままであることに注意してください。 これは、Clearメソッドが各アドレスに格納されている値を更新したために発生します。
文字列を使用してテストする
前に、文字列が 変更できない 型であることを学習しました。 文字列が参照型であっても、配列とは異なり、一度割り当てられた文字列の値を変更することはできません。
string.Replaceやstring.ToUpperなどのメソッドを使用している場合は、これに気付いたかもしれません。 このタスクでは、文字列を操作するときに見つかった一般的なエラーを修正する方法について説明します。
Visual Studio Code エディターで、前の演習の既存のコードを削除します。
Visual Studio Code エディターに次のコードを入力します。
string status = "Healthy"; Console.WriteLine($"Start: {status}"); SetHealth(status, false); Console.WriteLine($"End: {status}"); void SetHealth(string status, bool isHealthy) { status = (isHealthy ? "Healthy" : "Unhealthy"); Console.WriteLine($"Middle: {status}"); }コードを保存して実行し、次の出力を確認します。
Start: Healthy Middle: Unhealthy End: HealthySetHealthメソッドが状態を出力しなかった場合は、メソッドが正しく実行されなかったと想定している可能性があります。 代わりに、"Unhealthy" という値を持つ新しい文字列が作成され、メソッド スコープで失われました。この問題を解決するには、代わりにグローバル状態変数を使用するように
SetHealthを変更します。次のようにコードを更新します。
string status = "Healthy"; Console.WriteLine($"Start: {status}"); SetHealth(false); Console.WriteLine($"End: {status}"); void SetHealth(bool isHealthy) { status = (isHealthy ? "Healthy" : "Unhealthy"); Console.WriteLine($"Middle: {status}"); }このコードでは、グローバル
status変数を新しい文字列値で上書きします。コードを保存して実行し、次の出力を確認します。
Start: Healthy Middle: Unhealthy End: Unhealthy更新された文字列がキャプチャされ、正しく格納されるようになりました。
まとめ
これまでに、値型と参照型のパラメーターについて学習した内容を次に示します。
- 変数は、値型と参照型として分類できます。
- 値型には直接値が含まれており、参照型には値のアドレスが格納されます。
- 値型引数を使用するメソッドは、値の独自のコピーを作成します。
- 配列パラメーターに対して変更を実行するメソッドは、元の入力配列に影響します。
- 文字列は変更できない参照型です。
- 文字列パラメーターに対して変更を実行するメソッドは、元の文字列には影響しません。