C#で可変長引数を効率的に活用する手法

メソッドオーバーロードでは、異なる数の引数を処理するために同名メソッドを複数定義できますが、引数の数が動的に変化するケースでは適切な解決策ではありません。例えば整数値の最大値を求める場合、次のような実装が考えられます:

class Calculator
{
    public static int FindMaximum(int a, int b)
    {
        return a >= b ? a : b;
    }
    
    public static int FindMaximum(int a, int b, int c)
    {
        int result = a;
        if (b > result) result = b;
        if (c > result) result = c;
        return result;
    }
}

引数の数が不明確な場合、配列を引数として渡す方法が有効です:

class Calculator
{
    public static int FindMaximum(int[] values)
    {
        if (values == null || values.Length == 0)
        {
            throw new ArgumentException("引数が空です");
        }
        
        int largest = values[0];
        for (int i = 1; i < values.Length; i++)
        {
            if (values[i] > largest)
            {
                largest = values[i];
            }
        }
        return largest;
    }
}

この実装では、2つの整数を比較する際は以下のように配列を明示的に生成する必要があります:

int[] data = new int[] { x, y };
int max = Calculator.FindMaximum(data);

配列生成の手間を解消するため、params修飾子を使用します:

class Calculator
{
    public static int FindMaximum(params int[] values)
    {
        if (values.Length == 0)
        {
            throw new ArgumentException("引数が指定されていません");
        }
        
        int maxVal = int.MinValue;
        foreach (var num in values)
        {
            if (num > maxVal) maxVal = num;
        }
        return maxVal;
    }
}

これにより、任意の数の引数を直接指定できます:
int result = Calculator.FindMaximum(10, 20, 30, 40);

params配列を利用する際の重要な制約:

  1. 多次元配列には適用不可。コンパイルエラーとなる
  2. メソッドシグネチャの重複とみなされるため、params有無でのみ区別するオーバーロードは禁止
  3. refout修飾子と併用不可
  4. メソッドの最後の引数にのみ指定可能。1メソッドあたり1つまで
  5. 明示的な引数数を持つオーバーロードが優先される仕組み
  6. 引数パターンが重複するオーバーロード定義はコンパイルエラー

オブジェクト型の可変長引数が必要な場合はparams object[]を使用可能です。ただし、パフォーマンスを考慮し、基本データ型の場合は型指定したparams配列の利用が推奨されます。

タグ: C# メソッドオーバーロード paramsキーワード 可変長引数

5月19日 14:41 投稿