これまで、以下のようなコードを面倒に感じたことはありませんか?
static void Main() { try { Console.WriteLine(int.Parse("123")); //--- intに変換できなかったら例外発生! } catch { //--- 失敗したとき } }
絶対失敗しないと保証されているなら例外処理は要らないかもしれませんが、「失敗するかもしれない」と考えなければならないのがプログラミングの常なので、やっぱり先のようになります。でもこれはさすがに長過ぎる。なので少し簡略化して以下のように書く場合がほとんどだったでしょう。
static void Main() { int value; //--- イチイチ前に変数を宣言 if (int.TryParse("123", out value)) Console.WriteLine(value); }
TryParseであればif文で済むのでそれほど仰々しくもありません。でも戻り値として受けられないので、outを使って引数から結果を受ける必要があります。その結果、イチイチif文の前に変数を宣言せねばならないという別の面倒が訪れました。
変数宣言式
この問題を解決するために「変数宣言式」が導入されました。その名の通り、式の途中で変数を宣言して利用することができます。
static void Main() { if (int.TryParse("123", out var value)); //--- 式の途中で変数を宣言して Console.WriteLine(value); //--- それを利用する }
変数のスコープ
式の途中で宣言した変数のスコープは以下のようになります。
static void Main() { if (int.TryParse("123", out var value)); //--- if文の条件式内で変数を宣言 { //--- value変数のスコープはif文の中のみ Console.WriteLine(value); } Console.WriteLine(value); //--- これはコンパイルエラー } static void Main() { var result = int.TryParse("123", out var value)); if (result) { //--- value変数のスコープは関数内なのでOK Console.WriteLine(value); } Console.WriteLine(value); //--- こっちももちろんOK }
変数のスコープが最少になるので変数名の衝突などが起こりにくくなり、コードがシンプルになると思います。
逆コンパイル
if文の条件式内で変数を切った場合、その変数のスコープはif文の中のみでした。なので、以下のように変数名が同じものを連続して書くことができます。
static void Main() { if (int.TryParse("123", out var value)) Console.WriteLine(value); if (int.TryParse("456", out var value)) Console.WriteLine(value); }
では、このコードはどのように展開されるのでしょうか?ILSpyで逆コンパイルして実際に試してみました。結果は次のようになります。
static void Main() { int value; //--- 既存の書き方と同じように展開される if (int.TryParse("123", out value)) { Console.WriteLine(value); } int value2; //--- ちゃんと別物として解釈されている if (int.TryParse("456", out value2)) { Console.WriteLine(value2); } }
このように、基本的にはC# 5.0までのコードと同じように展開されます。また、元々の変数名はどちらもvalueですが、後者の変数名がvalue2になっています。ILレベルではどちらも変数名はvalueのまま表現されているのですが、ILSpyがC#として表現する際に変数名をよしなに変えてくれています。どちらも素直にvalueのまま展開してしまうとC#として変数名がぶつかってしまいますが、元々取り扱うスコープが異なるものなので、分かりやすく調整してくれているということですね。
2014/10/06 : 追記
別に検討中の機能との兼ね合いでC# 6.0での搭載は見送られました。詳細は以下から確認することができます。