C#で配列のサイズ変更や要素を末尾に追加する

C#で宣言済みの配列のサイズを変更するためにはArray.Resizeを使用します。末尾に要素を追加する場合、Resizeで+1した後最後にデータを追加します。

実装コードは以下の通りです。

// 100 → 200へ配列のサイズを変更
int[] array = new int[100];
Array.Resize(ref array, 200/*新しいサイズ*/);

// 201件目に要素を追加
Array.Resize(ref array, array.Length + 1);
array[Length -1] = 999;

このように簡単に実現できます。

で、Array.Resizeの中身の実装を確認すると以下のように、ただ単に新しいサイズの配列を宣言して内容を全部コピーしているだけみたいです。

// Array.Resizeの実際のソースコード(抜粋
public static void Resize<T>(ref T[] array, int newSize)
{
    T[] larray = array;                
    if (larray == null)
    {
        array = new T[newSize];
        return;
    }

    if (larray.Length != newSize)
    {
        T[] newArray = new T[newSize];
        Array.Copy(larray, 0, newArray, 0,  larray.Length > newSize? newSize : larray.Length);
        array = newArray;
    }
}

なので、この操作は「パフォーマンスがとっても悪そう」や「一時的に倍のメモリが必要」など色々デメリットが考えられます。が、それらはいったん無視して、Array.Resizeを利用しつつ配列を直接サイズ変更できる仕組みを考えてみました。

配列に直接サイズ変更・要素追加できるメソッドを追加する

C#の「拡張メソッド」という機能を使って配列へサイズを変更するメソッドを追加したいと思います。

実装は以下の通りです。

// 配列を拡張するための拡張クラス
public static class ArrayExtension
{
    // 配列の要素数の変更
    public static T[] Resize<T>(this T[] array, int newSize)
    {
        Array.Resize(ref array, newSize);
        return array;
    }

    // 配列を+1して最後にデータを追加
    public static T[] Add<T>(this T[] array, T item)
    {
        Array.Resize(ref array, array.Length + 1);
        array[array.Length - 1] = item;
        return array;
    }
}

使い方は以下の通りです。

public static void Main(string[] args)
{
    // 変更対象の配列
    int[] a = new int[100];
    // 100 → 200へ配列のサイズを変更
    a = a.Resize(200);
    // 201件目に"10"を追加
    a = a.Add(10);


    a.ForEach(item => Console.Write($"{item}, "));

    Console.ReadLine();
}

作用が新しい参照になるため、操作結果は変数で受ける必要があります。C#7.2以降は拡張メソッドにrefキーワードが付与できるのでもっとスマートにできそうです。