C# 3.0をはじめよう!!
C# 3.0ってなに? 以前のバージョンのC# 2.0から様々な 機能拡張が行われた。 .NET Framework 3.5と同時に出荷された C#の最新バージョン 以前のバージョンのC# 2.0から様々な 機能拡張が行われた。 でも、ランタイムであるCLRのバージョン は変わっていない(コンパイラが変わった)。
どう変わったの? などの新しい言語仕様、機能が追加された。 型推論 自動プロパティ クラスイニシャライザ コレクションイニシャライザ ラムダ式 拡張メソッド 匿名型 LINQ 式ツリー などの新しい言語仕様、機能が追加された。
何故使うの? 開発効率が高いから (型推論、拡張メソッド、ラムダ式、etc) .NET Framework 3.5 Client Profileの存在 → 従来の.NET Framework 2.0よりもインス トールサイズが小さい(197MB →26.5MB) 「ラムダ式」とか言いたいから
どうすれば使える? 他にもオープンソースの無償のIDE、 SharpDevelopなんてのもある 開発には「Visual Studio 2008」が必要 無償版の「Visual C# 2008 Express」でも可 他にもオープンソースの無償のIDE、 SharpDevelopなんてのもある もちろんテキストエディタと コンパイラ(SDK)だけでも可 (^^
新機能の紹介 型推論 自動プロパティ クラスイニシャライザ コレクションイニシャライザ ラムダ式 拡張メソッド 匿名型 LINQ
型推論 変数宣言の時、型を省略できるようになった。 といっても、型が判断できない時は使えない。 あくまでも、型の記述を省略できるだけなので var s = “hello”; // 文字列型 var i = 1; // 数値型 変数宣言の時、型を省略できるようになった。 といっても、型が判断できない時は使えない。 var s; // コンパイルエラー あくまでも、型の記述を省略できるだけなので var s = “hello”; S = 1; // コンパイルエラー 違う型の代入はできない(Variantとかではない)。
型推論 クラスのフィールド宣言では使えません!! ローカルなスコープ(メソッドの中)でのみ使用可能。 class Person { var firstName = “”; // NG } クラスのフィールド宣言では使えません!! ローカルなスコープ(メソッドの中)でのみ使用可能。 var strCollection = new List<string>(); var strIntDict = new Dictionary<string, int>(); // こんなん二回も書いてられない var complex = new Dictionary<string, List<int>>(); 一番役に立つときは、やっぱりジェネリックの時かな
型推論 デリゲートの時は省略できない(当たり前?)。 型推論の是非については、色々あるようですが 便利なので、気にせずがんがん使いましょう。 void DoSomething(string arg) { // do something } var action = DoSomething; // コンパイルエラー // デリゲートの型を指定する必要がある Action<string> action = DoSomething; デリゲートの時は省略できない(当たり前?)。 型推論の是非については、色々あるようですが 便利なので、気にせずがんがん使いましょう。
新機能の紹介 型推論 自動プロパティ クラスイニシャライザ コレクションイニシャライザ ラムダ式 拡張メソッド 匿名型 LINQ
自動プロパティ C# 1.0~2.0の場合 using System; class Person { private string firstName; private string lastName; public string FirstName { get { return firstName; } set { firstName = value; } } public string LastName { get { return lastName; } set { lastName = value; } C# 1.0~2.0の場合
自動プロパティ C# 3.0の場合 get、setを記述するだけでそれに対応したフィールドが 自動生成されるようになった。 using System; class Person { public string FirstName { get; set; } public string LastName { C# 3.0の場合 get、setを記述するだけでそれに対応したフィールドが 自動生成されるようになった。
自動プロパティ でも、getだけとか、setだけとかは無理。 必ず両方宣言する必要がある。 使えね~ using System; class Person { public string FirstName { get; // NG } public string LastName { set; // NG でも、getだけとか、setだけとかは無理。 必ず両方宣言する必要がある。 使えね~
自動プロパティ プロパティの初期値はコンストラクタで設定するしかない。 using System; class Person { public string FirstName { get; set; } public string LastName { public Person() { this.FirstName = “名無しさん”; this.LastName = “”; プロパティの初期値はコンストラクタで設定するしかない。
新機能の紹介 型推論 自動プロパティ クラスイニシャライザ コレクションイニシャライザ ラムダ式 拡張メソッド 匿名型 LINQ
クラスイニシャライザ クラスの初期化時にプロパティを設定できるようになった。 昔はこんな↓コンストラクタを用意したよね。 var person = new Person { FirstName = “Kouji”, LastName = “Yamaguchi” }; クラスの初期化時にプロパティを設定できるようになった。 昔はこんな↓コンストラクタを用意したよね。 public Person(string firstName, string lastName) { this.firstName = firstName; this.lastName = lastName; } これからは要らないかも!?って、んなわきゃない。
クラスイニシャライザ 必須のプロパティはコンストラクタの引数で、そうでないプロパティはクラスイニシャライザで設定するという使い分け。 using System; class Person { public string FirstName { get; set; } public string LastName { public int Age { public Person(string firstName, string lastName) { this.FirstName = firstName; this.LastName = lastName;
新機能の紹介 型推論 自動プロパティ クラスイニシャライザ コレクションイニシャライザ ラムダ式 拡張メソッド 匿名型 LINQ
コレクションイニシャライザ コレクション(配列、リスト)の初期化時に、その要素を 指定できるようになった。 var collection = new List<string>() { “John”, “Bob”, “Kitty” }; コレクション(配列、リスト)の初期化時に、その要素を 指定できるようになった。 配列の場合は型を省略することもできる。 // string型の配列 var array = new[] { “John”, “Bob”, “Kitty” };
コレクションイニシャライザ ただし、要素の型は統一する必要がある。 ディクショナリの初期化もできるでよ。 // コンパイルエラー var array = new[] { “John”, // 文字列 1, // 数値 true // 真偽値 }; var dict = new Dictionary<string, int>() { { “John”, 20 }, { “Bob”, 18}, { “Kitty”, 12 } }; ディクショナリの初期化もできるでよ。
コレクションイニシャライザ ちなみにコレクションイニシャライザで初期化できる クラスの条件は、 これが成立する。 System.Collections.IEnumerableを実装している 引数を一つ以上とるpublicなAddメソッドを実装している。 class FakeCollection : IEnumerable { public void Add(string value) { } IEnumerator IEnumerable.GetEnumerator() { yield break; } var c = new FakeCollection { “Hoge”, “Fuga” }; これが成立する。
新機能の紹介 型推論 自動プロパティ クラスイニシャライザ コレクションイニシャライザ ラムダ式 拡張メソッド 匿名型 LINQ
ラムダ式 匿名メソッドってあったよね? 名前の無いメソッドを定義できるやつ。 これが、こんな感じ↓で書けるようになった。 Action<string> showMsg = delegate(string msg) { Console.WriteLine(msg); }; showMsg(“Hello, World”); 匿名メソッドってあったよね? 名前の無いメソッドを定義できるやつ。 Action<string> showMsg = (msg) => Console.WriteLine(msg); showMsg(“Hello, World”); これが、こんな感じ↓で書けるようになった。
ラムダ式 引数が一つの場合は、引数の括弧を省略できる。 引数が無い場合は、括弧だけでOK。 Action<string> showMsg = msg => Console.WriteLine(msg); 引数が一つの場合は、引数の括弧を省略できる。 Action newLine = () => Console.WriteLine(); 引数が無い場合は、括弧だけでOK。 Func<string> getMsg = () => “Hello, World”; 処理が一行の場合は返り値を返すのにreturnはいらない。 Func<bool, string> getMsg = (value) => { return value == “Hoge”; }; 処理が複数行に渡る場合は、returnが必要になる。
ラムダ式 すごい便利ですね!! もちろんクロージャとしても機能する。 var list = new List<string> { “John”, “Bob”, “Kitty” }; // 簡潔に記述できる。 list.ForEach(s => Console.WriteLine(s)); すごい便利ですね!! もちろんクロージャとしても機能する。 var i = 0; Action increment = () => i++; // iがインクリメントされる。 increment()
新機能の紹介 型推論 自動プロパティ クラスイニシャライザ コレクションイニシャライザ ラムダ式 拡張メソッド 匿名型 LINQ
拡張メソッド 今までちょっとした便利機能はユーティリティクラス (staticなメソッドのみのクラス)を作って実装していた。 public static class StringUtils { // 指定した文字列の末尾の文字を取得するメソッド public static char Last(string value) { return value[value.Length - 1]; } // e Console.WriteLine(StringUtils.Last(“Hoge”)); 今までちょっとした便利機能はユーティリティクラス (staticなメソッドのみのクラス)を作って実装していた。 これでも十分事は足りるけど、やっぱり本当はstringクラスに「Last」というメソッドが欲しい。 そこで「拡張メソッド」ですよ。
拡張メソッド thisキーワードを使って引数を定義すると・・・ その引数の型のメソッドのように振る舞う事ができる。 public static class StringUtils { // 指定した文字列の末尾の文字を取得するメソッド public static char Last(this string value) { return value[value.Length - 1]; } // e Console.WriteLine(“Hoge”.Last()); thisキーワードを使って引数を定義すると・・・ その引数の型のメソッドのように振る舞う事ができる。 これは基本ライブラリのクラス(stringとかintとか)に メソッドを追加できる(ように見える)という事。 ちなみに、拡張メソッドを定義するクラスは必ず staticにする必要がある。
拡張メソッド 便利な拡張メソッドとして、 最大値・最小値・平均値を求めるもの オブジェクトの配列からディクショナリに変換するもの var nums = new[] { 1, 5, 2, 4, 10, 16, 30, 88 }; Console.WriteLine(“最大値: ” + nums.Max()); Console.WriteLine(“最小値: ” + nums.Min()); Console.WriteLine(“平均値: ” + nums.Average()); var objs = new[] { new Person(“John”, “Sykes”), new Person(“Yngwei”, “Malmsteen”), new Person(“Ritchie”, “Blackmore”) } var dict = objs.ToDictionary(o => o.FirstName, o => o.LastName); オブジェクトの配列からディクショナリに変換するもの なんてのがある。
拡張メソッド 拡張メソッドはインターフェースにも定義できるので、 これを利用すると多重継承、Mix-In(みたいなの) ができるようになる。 interface IHoge { } interface IFuga { } static class HogeExtension { public static void HelloHoge(this IHoge hoge) { } static class FugaExtension { public static void HelloFuga(this IFuga fuga) { class HogeFuga : IHoge, IFuga { var o = new HogeFuga(); o.HelloHoge(); o.HelloFuga(); これを利用すると多重継承、Mix-In(みたいなの) ができるようになる。
新機能の紹介 型推論 自動プロパティ クラスイニシャライザ コレクションイニシャライザ ラムダ式 拡張メソッド 匿名型 LINQ
匿名型 名前の無い、匿名のクラスを定義(プロパティのみ)できる。 ただし、ローカルスコープ(メソッド内)でしか使えない。 var obj = new { Row = 1, Column = 1, Value = “John” }; // Row = 1, Column = 1, Value = John Console.WriteLine( “Row = {0}, Column = {1}, Value = {2}”, // プロパティとしてアクセスできる。 obj.Row, obj.Column, obj.Value ); 名前の無い、匿名のクラスを定義(プロパティのみ)できる。 ただし、ローカルスコープ(メソッド内)でしか使えない。 普通は一時的なデータの入れ物として使う。 今までディクショナリとかインナークラスとかでやってた事が、これで少しだけ楽になる。
匿名型 メソッドは定義できないけど、デリゲートのプロパティを 定義すればメソッドのように振る舞える。 なにかに使えるかも!? var obj = new { DoSomething = (Action<string>)(msg => Console.WriteLine(msg)) }; obj.DoSomething(); メソッドは定義できないけど、デリゲートのプロパティを 定義すればメソッドのように振る舞える。 なにかに使えるかも!?
匿名型 例えば、↓こんなメソッドがあった場合 ディクショナリを初期化して渡すのって、結構だるいよね。 void DoSomething(IDictionary<string, object> keyValues) { } 例えば、↓こんなメソッドがあった場合 DoSomething(new Dictionary<string, object> { { “Product”, “Hoge” }, { “Price”, 100 } }); ディクショナリを初期化して渡すのって、結構だるいよね。 DoSomething(new { Product = “Hoge”, Price = 100 }); これが匿名クラスで指定できたら、楽じゃね?
匿名型 そんな時は、↓こんなクラスを作れば、 static class ObjectExtension { // object型をIDictionary<string, object>型に変換する。 public static IDictionary<string, object> ToDict(this object obj) { var tp = obj.GetType(); var props = tp.GetProperties( BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty ); return props.ToDictionary( p => p.Name, p => tp.InvokeMember( p.Name, BindingFlags.GetProperty, null, obj, null ) }
匿名型 ↓こんな風に書けます。 DoSomething(new { Product = “Hoge”, Price = 100 }.ToDict()); ↓こんな風に書けます。
新機能の紹介 型推論 自動プロパティ クラスイニシャライザ コレクションイニシャライザ ラムダ式 拡張メソッド 匿名型 LINQ
LINQ Language Integrated Query(統合言語クエリ) var array = new[] { “John”, “Bob”, “Sandy” }; var query = from o in array where o.Contains(“o”) select o; // John // Bob foreach(var o in query) Console.WriteLine(o); Language Integrated Query(統合言語クエリ) コレクション(リスト、配列)に対して、SQLのようなクエリ言語で検索がかけられる。
LINQ LINQの特徴は共通のクエリ言語を使って、 異なる種類のデータソースに対して検索が行えること。 例えば、 オブジェクトのコレクションに対して検索を行う LINQ to Object SQLサーバーに対して検索を行う LINQ to SQL (DLINQ) XMLドキュメントに対して検索を行う LINQ to XML (XLINQ) が用意されている。
LINQ LINQのコンパイル時の処理フロー 演算子が対応する拡張メソッドに置き換わる。 プロバイダ毎のクエリに変換される。 var query = from o in array where o.Contains(“o”) select o; LINQのコンパイル時の処理フロー 演算子が対応する拡張メソッドに置き換わる。 var query = array.Where(o => o.Contains(“o”)).Select(o => o); プロバイダ毎のクエリに変換される。 LINQ to Object LINQ to SQL LINQ to XML SQLクエリ XPathクエリ
LINQ LINQで使用できる演算子 LINQに対応している拡張メソッド from [要素] in [コレクション] where [条件] join [要素] in [コレクション] on [左辺] equals [右辺] group [要素] by [キー] order by [キー] [ascending|decending] select [要素] LINQに対応している拡張メソッド Single, SingleOrDefault First, FirstOrDefault Last, LastOrDefault Count Take, TakeWhile Skip, SkipWhile Max, Min, Sum
(DLINQのデモ)
まとめ とりあえず皆さんC# 3.0をはじめましょう \(^o^)/ C# 3.0の新しい機能は全てLINQの為にある。 LINQに魅力を感じるかどうかがC# 3.0を導入するかどうかのポイントになる。 LINQを使いこなせなければ、C# 3.0を使うメリットはあまり無いかも? まぁ、何にせよ開発効率とおもしろさは間違いなく向上するので、やって損は無い。 とりあえず皆さんC# 3.0をはじめましょう \(^o^)/
(おわり)