C#3.0ではLINQが追加されました。 それに伴い、LINQの可読性を上げるための機能もC#3.0には追加されています。 &bold(){目次} #contents() *暗黙的に型指定されたローカル変数 ・明示的に型を指定することなく、ローカル変数を宣言することができようになった ・varキーワードを使用する ・コンパイル時に適切な型が割り当たる ・フィールドでは使用不可 ・VB6のVariantと異なり、変数宣言時に初期化が必要 ・VB6のVariantと異なり、型変換は出来ない ・型名の冗長さを省く場合や、匿名型を使用した場合に用いる #highlight(csharp){{ class Program { //フィールドでは使用不可 //var a = 123; static void Main(string[] args) { var i = 123; var d = 12.3M; var str = "abc"; var dt = DateTime.Now; //変数宣言時に初期化が必要 //var b; //型変換は出来ない //i = "abc"; //型の冗長さを省く場合 var obj1 = new Myclass(); //匿名型を使用した場合 var obj2 = new { Name = "abc" }; } } class Myclass { } }} *暗黙的に型指定された配列 ・newで配列を作成する際、newの後ろの型が省略可能となった ・コンパイル時に{} の中身から適切な型が割り当たる ・複数の型が含まれる場合、コンパイルエラーとなる #highlight(csharp){{ class Program { static void Main(string[] args) { var i = new[] { 1, 2, 3, }; var d = new[] { 1.1, 2.2, 3.3 }; var str = new[] { "abc", "def", "ghi" }; //複数の型が含まれる場合、コンパイルエラーとなる //var obj = new[] { 1, "abc", 2 }; //匿名型を使用した場合 var persons = new[]{ new{Name = "Taro",Age = 20}, new{Name = "Jiro",Age = 18} }; } } }} *オブジェクト初期化子 ・オブジェクトの初期化が簡潔に記述可能となった ・中カッコ{ }内で初期化を行う #highlight(csharp){{ class Program { static void Main(string[] args) { //C#3.0の場合 var person3 = new Person { Age = 20, Name = "Taro" }; //C#2.0の場合 Person person2 = new Person(); person2.Age = 20; person2.Name = "Taro"; } } class Person { public string m_name; public int m_age; public string Name { get { return m_name; } set { m_name = value; } } public int Age { get { return m_age; } set { m_age = value; } } } }} *コレクション初期化子 ・コレクションの初期化が簡潔に記述可能となった ・中カッコ{ }内で初期化を行う #highlight(csharp){{ class Program { static void Main(string[] args) { //C#3.0の場合 var list3 = new List<int> { 1, 2, 3 }; var dic3 = new Dictionary<string, int>() { { "a", 1 }, { "b", 2 }, { "c", 3 } }; //C#2.0の場合 List<int> list2 = new List<int>(); list2.Add(1); list2.Add(2); list2.Add(3); Dictionary<string, int> dic2 = new Dictionary<string, int>(); dic2.Add("a", 1); dic2.Add("b", 2); dic2.Add("c", 3); } } }} *自動プロパティ ・プロパティの記述が簡潔に記述可能となった ・コンパイル時、従来のプロパティが自動的に生成される ・get、set 両方を記述する必要がある ・読み取り専用のプロパティを作成するには、プライベートな set を用意する #highlight(csharp){{ class Person { public string Name { get; set; } } }} 上記クラスをコンパイルし[[Reflector for.NET>http://www.red-gate.com/products/reflector/]]を使用し生成ファイルを見ると、以下のフィールド、プロパティが自動生成されていることがわかる #highlight(csharp){{ internal class Person { // Fields private string <Name>k__BackingField; // Properties public string Name { get { return this.<Name>k__BackingField; } set { this.<Name>k__BackingField = value; } } } }} *匿名型 ・クラスを別途定義せずにオブジェクト生成が可能となった ・匿名型は、プログラマからはクラス名が不明のためvarキーワードを使用する ・コンパイル時、クラスが自動的に作成される ・同じ名前、同じ型、同じ並び順のプロパティを持つ匿名型は同一のクラスとなる ・主にLINQのselect旬で使用される機能 #highlight(csharp){{ class Program { static void Main(string[] args) { var obj1 = new { Name = "Taro", Age = 20 }; var obj2 = new { Name = "Jiro", Age = 18 }; if (obj1.GetType() == obj2.GetType()) { Console.WriteLine("同じ型"); } } } }} 上記クラスをコンパイルし[[Reflector for.NET>http://www.red-gate.com/products/reflector/]]を使用し生成ファイルを見ると、以下のクラスが自動生成されていることがわかる #highlight(csharp){{ internal sealed class <>f__AnonymousType0<<Name>j__TPar, <Age>j__TPar> { // Fields private readonly <Age>j__TPar <Age>i__Field; private readonly <Name>j__TPar <Name>i__Field; // Methods public <>f__AnonymousType0(<Name>j__TPar Name, <Age>j__TPar Age) { this.<Name>i__Field = Name; this.<Age>i__Field = Age; } // Properties public <Age>j__TPar Age { get { return this.<Age>i__Field; } } public <Name>j__TPar Name { get { return this.<Name>i__Field; } } } }} *拡張メソッド ・既存クラスを継承することなく、既存クラスにインスタンスメソッドを追加出来る機能 ・非ジェネリックのstaticクラス内にてstaticメソッドで宣言する必要がある ・this[[修飾子]]にて、拡張メソッドを追加する型を指定する ・拡張メソッドを含む[[名前空間]]をusing文で指定すると有効となる #highlight(csharp){{ //拡張メソッドを含む名前空間を指定すると有効となる using B; namespace A { class Program { static void Main(string[] args) { //拡張メソッドの呼び出し "abc".Print(); //通常のstaticメソッドとしての呼び出しも可能 StingExtensions.Print("abc"); } } } namespace B { static class StingExtensions { //拡張メソッド public static void Print(this string str) { System.Console.WriteLine(str); } } } }} ・拡張メソッドとインスタンスメソッドが重複した場合、インスタンスメソッドが優先される #highlight(csharp){{ namespace A { class Program { static void Main(string[] args) { X obj = new X(); //クラスXのMethod()が呼ばれる obj.Method(); } } class X { public void Method() { } } static class Y { public static void Method(this X x) { } } } }} *ラムダ式 ・ラムダ式は、式とステートメントを含めることができる匿名関数であり、デリゲート型または式ツリー型を作成するために使用される ・[[演算子]] => を使用する ・演算子 => の左辺で入力パラメータを指定し、右辺で式、またはステートメントを指定する デリゲート型を作成する場合 #highlight(csharp){{ namespace LambdaExpression { delegate int D(int x, int y); class Program { static void Main(string[] args) { //C#1.0 //外部メソッドを用意する必要があった D d1 = new D(Add); //C#2.0 //匿名メソッド使用 { }内に直接記述可能となった D d2 = delegate(int x, int y) { return x + y; }; //C#3.0 //ラムダ式使用 匿名メソッドより簡略し記述可能となった D d3 = (x, y) => x + y; //以下の記述も可 //D d3 = (int x, int y) => { return x + y; }; //D d3 = (int x, int y) => return x + y; //D d3 = (int x, int y) => x + y; Console.WriteLine(d1(1, 2)); Console.WriteLine(d2(1, 2)); Console.WriteLine(d3(1, 2)); } static int Add(int x, int y) { return x + y; } } } }} 式ツリー型を作成する場合 #highlight(csharp){{ using System.Linq.Expressions; namespace LambdaExpression { class Program { static void Main(string[] args) { //ラムダ式をデリゲートに代入すると匿名メソッドとなる Func<int, int, int> f = (x, y) => x + y; Console.WriteLine(f(1, 2)); //ラムダ式をExpression式に代入すると式ツリー型となる Expression<Func<int, int, int>> e = (x, y) => x + y; var bin = (BinaryExpression)e.Body; var p1 = (ParameterExpression)bin.Left; var p2 = (ParameterExpression)bin.Right; Console.WriteLine(bin); Console.WriteLine(p1); Console.WriteLine(p2); } } } }} *LINQ ・LINQは、Language Integrated Query(統合言語クエリ)の略 ・LINQにより、異なる種類のデータに対して統一したクエリ構文でアクセスが可能となった ・LINQにより、C#、VB.NETのコード内にクエリを記述することが出来る ・LINQにより、コンパイル時の型チェック、IntelliSenseの使用がクエリに対し可能となった ・扱えるデータは主に以下となる&br()オブジェクト(LINQ to Objects)&br()XML(LINQ to XML)&br()ADO.NETのDataSet(LINQ to DataSet)&br()SQLサーバのデータベース(LINQ to SQL)&br()ADO.NET Entity Frameworkから提供される概念エンティティ(LINQ to Entities) C$3.0でのLINQ to Objectsの例 #highlight(csharp){{ class Program { static void Main(string[] args) { var persons = new[] { new { Name="Taro", Age=20 }, new { Name="Jiro", Age=18 } }; var adults = from person in persons where person.Age >= 20 select new { person.Name, person.Age }; foreach (var adult in adults) { Console.WriteLine(adult.Name + "," + adult.Age); } } } }} C#2.0で同様のコードを記述した場合 #highlight(csharp){{ class Program { static void Main(string[] args) { List<Person> persons = new List<Person>(); persons.Add(new Person("Taro", 20)); persons.Add(new Person("Jiro", 18)); List<Person> adults = new List<Person>(); foreach (Person person in persons) { if (person.Age >= 20) { Person adult = new Person(person.Name, person.Age); adults.Add(adult); } } foreach (Person adult in adults) { Console.WriteLine(adult.Name + "," + adult.Age); } } } class Person { public string m_name; public int m_age; public Person(string name, int age) { m_name = name; m_age = age; } public string Name { get { return m_name; } set { m_name = value; } } public int Age { get { return m_age; } set { m_age = value; } } } }} 参考 C# 3.0 の概要 [[http://www.microsoft.com/japan/msdn/net/bb308966.aspx>http://www.microsoft.com/japan/msdn/net/bb308966.aspx]]