|
|
連載:C# 4入門
第4回 引数の省略と順番の変更
株式会社ピーデー 川俣 晶
2010/10/15 |
|
|
可変値指定不可能
ならば、外部から動的に省略時のデフォルト引数の値を指定できるように拡張してやろうと、以下のように書き直すとコンパイルできない。
using System;
class Program
{
private static string defaultValue;
private static void myMethod(int a, string b = defaultValue)
{
if (b != null)
Console.WriteLine("{0}さんはテストを受けました。", b);
if (a >= 0)
Console.WriteLine("{0}点でした。", a);
}
static void Main(string[] args)
{
defaultValue = null;
myMethod(100);
myMethod(50, "タロウ");
}
}
|
|
リスト4(コンパイルできない) |
なぜコンパイルできないのかといえば、引数の省略時の値は定数値に限られるからだ。
なぜ定数値に限られるのかといえば、実はこの機能は「引数が省略されたときに補われる値」なのではなく、「引数が省略されたときに補ってほしい値をメタデータで公開している」からなのだ。メタデータに記録する値は定数値である必要がある。つまり、計算の結果として得られるいかなる値も、省略時のデフォルトとして指定できない。どうしてもそれが必要なら、省略時のデフォルトとして無効の値を指定して、その値が指定されたらメソッド内で計算するしかない。
また、この前提から分かるとおり、デフォルト値は呼び出し側に記録される。だから、値を修正したとき、呼ばれる側だけでなく、呼ぶ側も再コンパイルが必要である。
定数の正しい意味
以下のコードはコンパイルして実行できる。
using System;
class Program
{
private const string data1 = "This is data1.";
private static string data2 { get { return data1; } }
private static readonly string data3 = data1;
private static void MyMethod(string a = data1)
{
Console.WriteLine(a);
}
static void Main(string[] args)
{
MyMethod();
}
}
|
|
リスト5 |
しかし、MyMethodメソッドの引数を以下のように直すと、通る場合と通らない場合がある。
○ MyMethod(string a = "This is constant.")
○ MyMethod(string a = data1)
× MyMethod(string a = data2)
× MyMethod(string a = data3)
これを見て分かるとおり、コンパイル時に確定する値はよいが、実行時に値が確定する方法は、たとえ固定値であっても指定できない。微妙で分かりにくい制約だが、同時に実装方法が透けて見えるような制約でもある。
無効値選定の重要性
すでに説明したとおり、この機能は「引数が省略されたときに渡してほしい値をメタデータで指定する」機能であって、メソッドそのものは、完全な引数をすべて受け取ることになる。つまり、呼ばれる側から見ると「引数が省略されて補われたデフォルト値」と「それと同じ値を渡しただけ」という状況が判別できない。
それ故に、以下のような条件を持つメソッドはうまく記述できない。
- 引数にint型の値を1つ持つ
- 引数の値はint型で表現できる範囲について全体で有効である
- 引数が省略された場合は特定のフィールドの値を使用する
このような場合は、null許容型を使うことで、完全ではないがうまく処理することができる。
using System;
class Program
{
private static int defaultValue;
private static void myMethod(int? x = null)
{
if (x == null)
Console.WriteLine(defaultValue);
else
Console.WriteLine(x);
}
static void Main(string[] args)
{
defaultValue = 123;
myMethod();
myMethod(456);
}
}
|
|
リスト6 |
この場合、int型で表現できる数値はすべて有効であり、引数省略のケースと識別できる。唯一、以下の2つの呼び出しは区別できないことになるが、これは区別できなくてもそれほど困る問題ではないだろう。
つまり、引数の省略とnull許容型の相性はとてもよい。null許容型を使わないプログラマーも、引数を省略する場面では使ってみるとよいのではないだろうか。
Insider.NET 記事ランキング
本日
月間