Ver. 3.0
C# 2.0 以前、「静的型付け言語は冗長な記述が多くてめんどくさい」などと言われることがありました。 例えば、以下の例について考えてみてください。
System.Collections.Generic.List<int> list = new System.Collections.Generic.List<int>();
「なんでこんな長ったらしい型名を左辺と右辺の両方で書かなきゃいけないんだ、 どっちか片方書けば、もう片方は推論できるだろう」という話です。
これに対して、C# 3.0 では、可能な限り型推論を行うような構文が追加されています。
var x = 1; なら x は int になる。
new int[] { 1, 2, 3 } を new[] { 1, 2, 3 } と書けるようになりました。
var anonymous = new { X = 1, Y = 2 }; みたいに、匿名のクラスを作ることができるようになりました。
var キーワードを用いて、 暗黙的に型付けされたローカル変数(Implicitly typed local variables)を定義できるようになりました。
var n = 1; var x = 1.0; var s = "test";
var を用いる際には、必ず初期値を伴う必要があります。
そして、初期値から、変数の型を自動判別してくれます。
上記の例では、
n は int、
x は double、
s は string 型の変数になります。
注意すべき点は、 あくまで型の自動判別・推定であって、 任意の型の値を代入できる万能な変数を作れるわけではないということです。 したがって、以下のように、初期値を伴わない宣言は(型の推定ができないので)エラーになります。
var n; // エラー。初期値が必要。
TypeName x = new TypeName(); というように、
式の両辺に型名を書かないといけないのは冗長ではあります。
var は、この冗長さを省くため、左辺側の型名を省略できる機能だと思ってください。
ちなみに、この機能は、後述する匿名型と併せて、 LINQ をより便利に使うためのものであって、 それ以外の場面ではあまり乱用すべきではないと思います。 型の自動判別・推定機構に頼らず、できる限りちゃんと型を明示すべきです。 むやみに型推定機能に頼ると、知らず知らずの間に int のつもりで使っていた変数が double になっていたということも起きかねません。
冗長性がエラー耐性になっている場合もあるので、
TypeName x = new TypeName(); という冗長な書き方も悪いことばかりではありません。
C# 3.0 では匿名型(anonymous type)を作成できるようになりました。 匿名型の作り方は以下の通りです。
var x = new { FamilyName = "糸色", FirstName="望"};
このようなコードから、自動的に、以下のような型が生成されます。
// ↓この __Anonymous という名前はプログラマが参照できるわけではない。 class __Anonymous1 { private string f1; private string f2; public __Anonymous1(string f1, string f2) { this.f1 = f1; this.f2 = f2; } public string FamilyName { get { return this.f1} }; public string FirstName { get { return this.f2} }; // あと、Equals, GetHashCode, ToString も実装 }
そして、変数 x に対して、 2つのプロパティ FamilyName と FirstName が使えます。
var x = new { FamilyName = "糸色", FirstName="望"}; Console.Write("{0}\n", x.FamilyName, x.FirstName);
自動生成されたクラスを見てのとおり、自動実装されたプロパティには set アクセサーがありません。 要するに、読み取り専用(immutable: 不変)になります。
通常のオブジェクト初期化子では、public な set アクセサーを持つプロパティしか初期化できませんでしたが、 匿名型の場合には、コンストラクター呼び出しに置き換えられます。
var p = new Point { X = 1, Y = 2 }; // Point p = new Point(); // p.X = 1; // p.Y = 2; // と同じ意味。 var anonymous = new { X = 1, Y = 2 }; // __Anonymous anonymous = new __Anonymous(1, 2); // みたいなコードが生成される。
ちなみに、以下のように、他のクラスのプロパティを初期化子に渡す場合には、 「プロパティ名 =」の部分を省略することもできます。 (初期化子で渡したプロパティの名前がそのまま匿名クラスでも使われます。)
struct A { public int X { set; get; } public int Y { set; get; } public int Z { set; get; } } class Program { static void Main(string[] args) { A a = new A { X = 0, Y = 1, Z = 2}; var b = new { a.X, a.Y }; //↑ new { X = a.X, Y = a.Y } と同じ意味。 Console.Write("{0}, {1}\n", b.X, b.Y); } }
まあ、匿名クラスは、その場限りの使い捨てなクラスになるわけで、 普通はあまり使うような機能ではありません。 基本的には、LINQ のための機能だと思っていいでしょう。 例えば、後述するクエリ式中で、以下のように利用します。
var list1 = from p in list where p.id <= 15 orderby p.id select new { p.FamilyName, p.FirstName };
new で配列を作成する際、 型を省略できるようになりました。
int[] array = new[] {1, 2, 3, 4};
見ての通り、 new の後ろの型を省略しています。 配列の型は、{} の中身の型から推定されます。 この例の場合、中身が 1, 2, 3, 4 といずれも int 型なので、 配列は int[] 型になります。
まあ、これだけだと、 ちょっとタイピングをサボれる程度ですが、 var および匿名型と組み合わせることによって、 真価が発揮されます。
var array = new[] { new {X = 0, Y = 1}, new {X = 3, Y = -1}, new {X = 7, Y = 3}, new {X = 13, Y = -5}, }; foreach(var p in array) Console.Write("{0}\n", p);
配列宣言の中身が匿名なんだから、 new の後ろにどういう型名を書いたらいいかわかるはずがないですからね。