演習 - Clear() と Resize() について詳しく調べる
- 15 分
物流会社向けのパレット トラッカーを開発し続ける中で、新しいパレットを追跡し、古いパレットを追跡システムから削除する必要が生じる可能性があります。 では、パレットの追加と削除が可能な追跡機能を作成するにはどうすればよいでしょうか?
配列メソッドを使用して配列のクリアとサイズ変更を行う
Array.Clear() メソッドを使用すると、配列内の特定の要素の内容を削除し、配列の既定値に置き換えることができます。 たとえば、string 配列内の要素をクリアすると、クリアされた値は null に置き換えられます。 同様に、int 配列内の要素をクリアすると、0 (ゼロ) に置き換えられます。
一方、Array.Resize() メソッドを使用すると、配列に要素を追加したり、配列から要素を削除したりできます。
前の演習のコードをすべて削除するか、行コメント演算子
//を使ってコメントアウトします。Visual Studio Code エディターで次のようにコードを更新します。
string[] pallets = [ "B14", "A11", "B12", "A13" ]; Console.WriteLine(""); Array.Clear(pallets, 0, 2); Console.WriteLine($"Clearing 2 ... count: {pallets.Length}"); foreach (var pallet in pallets) { Console.WriteLine($"-- {pallet}"); }注
この例では、C# 12 で導入されたコレクション式構文を使用します。
少し時間を取って、コード
Array.Clear(pallets, 0, 2);の行に注目します。ここでは、
Array.Clear()メソッドを使用して、pallets配列のインデックス0から始まる2個の要素に格納されている値をクリアします。Visual Studio Code の [ファイル] メニューで、[保存] を選択します。
コードをビルドまたは実行する前に、Program.cs ファイルを保存する必要があります。
[エクスプローラー] パネルで、TestProject フォルダーの場所にあるターミナルを開くには、TestProject を右クリックし、[統合ターミナルで開く] を選択します。
ターミナル パネルが開き、ターミナルが TestProject フォルダーの場所に対して開かれていることを示すコマンド プロンプトが含まれているはずです。
コードを実行するには、ターミナルのコマンド プロンプトで、「dotnet run」と入力し、Enter キーを押します。
注
"実行するプロジェクトが見つかりませんでした" というメッセージが表示された場合は、ターミナルのコマンド プロンプトに、予期されている TestProject フォルダーの場所が表示されていることを確かめます。 例:
C:\Users\someuser\Desktop\csharpprojects\TestProject>コードを実行すると、配列の最初の 2 つの要素に保存されていた値が消去されたことがわかります。
Lengthプロパティとforeachステートメントでは、要素はまだ存在していますが、空になっています。Clearing 2 ... count: 4 -- -- -- B12 -- A13
空の文字列と null
Array.Clear() を使用すると、クリアされた要素ではメモリ内の文字列が参照されなくなります。 実際、要素では何もポイントされていません。 何もポイントされていないというのは、最初は理解しにくいかもしれませんが、重要な概念です。
Array.Clear() メソッドの影響を受けた要素の値を取得しようとする場合、それは可能でしょうか?
クリアされた要素の値にアクセスする
クリアされた要素の値を見つけて、C# コンパイラが null 値でどのように動作するかを確認するには、2 つの方法が必要です。
次のように、
Array.Clear(pallets, 0, 2);コード行の周りに新しいコード行を挿入します。Console.WriteLine($"Before: {pallets[0]}"); Array.Clear(pallets, 0, 2); Console.WriteLine($"After: {pallets[0]}");コードが次のコード リストと一致していることを確認します。
string[] pallets = [ "B14", "A11", "B12", "A13" ]; Console.WriteLine(""); Console.WriteLine($"Before: {pallets[0]}"); Array.Clear(pallets, 0, 2); Console.WriteLine($"After: {pallets[0]}"); Console.WriteLine($"Clearing 2 ... count: {pallets.Length}"); foreach (var pallet in pallets) { Console.WriteLine($"-- {pallet}"); }コード ファイルを保存してから、Visual Studio Code を使ってコードを実行します。
次の出力が表示されます。
Before: B14 After: Clearing 2 ... count: 4 -- -- -- B12 -- A13
出力 After: の行に注目すると、pallets[0] に格納されている値は空の文字列であると思うかもしれません。 しかし、C# コンパイラでは、null 値は表示用に空の文字列に暗黙的に変換されます。
クリアされた要素で文字列ヘルパー メソッドを呼び出す
クリアされた後で pallets[0] に格納されている値が null であることを証明するため、ToLower() に対して pallets[0] メソッドを呼び出すようにコード例を変更します。 文字列の場合は、問題なく動作します。 しかし、null の場合は、コードによって例外がスローされます。
コンソールに
ToLower()を書き込むたびにpallets[0]メソッドを呼び出すには、次のようにコードを更新します。Console.WriteLine($"Before: {pallets[0].ToLower()}"); Array.Clear(pallets, 0, 2); Console.WriteLine($"After: {pallets[0].ToLower()}");あなたのコードが次のコード リストと一致することを確認してください。
string[] pallets = [ "B14", "A11", "B12", "A13" ]; Console.WriteLine(""); Console.WriteLine($"Before: {pallets[0].ToLower()}"); Array.Clear(pallets, 0, 2); Console.WriteLine($"After: {pallets[0].ToLower()}"); Console.WriteLine($"Clearing 2 ... count: {pallets.Length}"); foreach (var pallet in pallets) { Console.WriteLine($"-- {pallet}"); }コード ファイルを保存してから、Visual Studio Code を使ってコードを実行します。 今回は、コードを実行すると、重要なエラー メッセージが表示されます。 そのテキストを調べると、次のようなメッセージが見つかります。
System.NullReferenceException: Object reference not set to an instance of an object.この例外がスローされるのは、C# コンパイラによって null が空の文字列に暗黙的に変換される前に、
pallets[0]要素の内容に対してメソッドを呼び出そうとしたためです。この場合の教訓は、配列要素で値が参照されている場合は、
Array.Clear()によってそれが削除されるということです。 これを解決するために、値を出力しようとする前に null を確認できます。エラーを回避するには、null である可能性のある配列要素にアクセスする前に、
ifステートメントを追加します。
if (pallets[0] != null)
Console.WriteLine($"After: {pallets[0].ToLower()}");
配列のサイズを変更して要素をさらに追加する
次に、手順 1 のコード リストを修正して、配列のサイズを変更するためのコードを含めます。 完了すると、コードは次のコード リストと一致するはずです。
string[] pallets = ["B14", "A11", "B12", "A13" ]; Console.WriteLine(""); Array.Clear(pallets, 0, 2); Console.WriteLine($"Clearing 2 ... count: {pallets.Length}"); foreach (var pallet in pallets) { Console.WriteLine($"-- {pallet}"); } Console.WriteLine(""); Array.Resize(ref pallets, 6); Console.WriteLine($"Resizing 6 ... count: {pallets.Length}"); pallets[4] = "C01"; pallets[5] = "C02"; foreach (var pallet in pallets) { Console.WriteLine($"-- {pallet}"); }少し時間取って、行
Array.Resize(ref pallets, 6);に注目します。ここでは、
Resize()メソッドを呼び出し、palletsキーワードを使用して参照でref配列を渡しています。 場合によっては、メソッドに値渡し (既定) または参照渡し (ref キーワードを使用) で引数を渡す必要があります。 これが必要になる理由については、.NET でのオブジェクトの管理方法について、長くて複雑な説明が必要になります。 残念ながら、このモジュールの範囲を超えています。 疑わしい場合は、IntelliSense または Microsoft Docs で特定のメソッドを適切に呼び出す方法の例を調べることをお勧めします。この例では、
pallets配列のサイズを 4 要素から6に変更します。 新しい要素は、現在の要素の末尾に追加されます。 2 つの新しい要素は、値を代入するまでは null です。コード ファイルを保存してから、Visual Studio Code を使ってコードを実行します。 コードを実行すると、次の出力が表示されます。
Clearing 2 ... count: 4 -- -- -- B12 -- A13 Resizing 6 ... count: 6 -- -- -- B12 -- A13 -- C01 -- C02
配列のサイズを変更して要素を削除する
逆に、Array.Resize() を使用して配列の要素を削除することもできます。
Visual Studio Code エディターで次のようにコードを更新します。
string[] pallets = [ "B14", "A11", "B12", "A13" ]; Console.WriteLine(""); Array.Clear(pallets, 0, 2); Console.WriteLine($"Clearing 2 ... count: {pallets.Length}"); foreach (var pallet in pallets) { Console.WriteLine($"-- {pallet}"); } Console.WriteLine(""); Array.Resize(ref pallets, 6); Console.WriteLine($"Resizing 6 ... count: {pallets.Length}"); pallets[4] = "C01"; pallets[5] = "C02"; foreach (var pallet in pallets) { Console.WriteLine($"-- {pallet}"); } Console.WriteLine(""); Array.Resize(ref pallets, 3); Console.WriteLine($"Resizing 3 ... count: {pallets.Length}"); foreach (var pallet in pallets) { Console.WriteLine($"-- {pallet}"); }コード ファイルを保存してから、Visual Studio Code を使ってコードを実行します。 コードを実行すると、次の出力が表示されます。
Clearing 2 ... count: 4 -- -- -- B12 -- A13 Resizing 6 ... count: 6 -- -- -- B12 -- A13 -- C01 -- C02 Resizing 3 ... count: 3 -- -- -- B12Array.Resize()の呼び出しでは、最初の 2 つの null 要素が削除されなかったことに注意してください。 むしろ、最後の 3 つの要素が削除されています。 注目すべきは、文字列値が含まれていたにもかかわらず、最後の 3 つの要素が削除されたことです。
配列から null 要素を削除できるか
Array.Resize() メソッドが配列から空の要素を削除しない場合に、そのジョブを自動的に実行する別のヘルパー メソッドはあるのでしょうか? いいえ。 配列から空の要素を削除する最善の方法は、各項目を反復処理して変数 (カウンター) をインクリメントし、null 以外の要素の数をカウントすることです。 次に、カウンター変数のサイズで 2 番目の配列を作成します。 最後に、元の配列内の各要素をループし、null 以外の値を新しい配列にコピーします。
要点
このユニットで説明したいくつかの重要なアイデアを以下に示します。
- 配列内の要素の値を空にするには、
Clear()メソッドを使用します。 - 配列内の要素の数を変更し、配列の末尾の要素を削除または追加するには、
Resize()メソッドを使用します。 - 新しい配列要素とクリアされた要素は null になります。つまり、メモリ内の値はポイントされていません。