はじめに
C# 3.0では、言語的にいくつかの構文が追加されています。この追加は、かなりの部分において、統合言語クエリ(LINQ)をサポートするために行われた変更と言ってよいでしょう。追加された機能としては、ラムダ式、拡張メソッド、匿名型、暗黙的に型付けされたローカル変数、自動プロパティ、オブジェクト初期化子などがあります(他にも多数の機能があります)。
追加された構文の大部分は、ごく特定のニーズを満たすものであり、これによって既に確立されているコーディング手法やデザイン手法およびガイドラインの重要性が低下するようなことはありません。迷ったときは、新しい構文ではなく従来のガイドラインを優先してください。
MicrosoftのAnson Horton氏は、「The Evolution Of LINQ And Its Impact On The Design Of C#」という優れた記事の中で、LINQがC# 3.0のデザインにもたらす影響について論じるとともに、新しい言語機能を独特な観点から採り上げています。
ラムダ式
ラムダ式はC# 2.0の匿名メソッドが進化したものと考えられます。ラムダメソッドは、関数型プログラミング(計算を数学関数の評価として扱い、ステートや変動データを避ける枠組み)をC#で採用しようとしたものです。
ラムダ式はラムダ計算に基づいています。
使用時のヒント
- 同じコードを繰り返し使用する場合はラムダ式よりもメソッドを優先する。
- C# 2.0では匿名デリゲートが適切と思われる場合はラムダ式を優先する。
拡張メソッド
おそらく大いに賛否が分かれそうな追加構文の1つが拡張メソッドです。拡張メソッドを使用すると、どのクラスにも静的メソッドを「注入」(inject)することができます。拡張メソッドは基本的に、特定の型のインスタンスで動作する静的メソッドを作成するためのいわゆる構文糖(syntactic sugar)です。C# 3.0以前は、一般的なユーティリティメソッドを次のように書いていました。
public static bool IsStringPlural(String text, CultureInfo cultureInfo) {/* ... */}
このメソッドは次のような方法で呼び出されます。
String text = "languages"; Boolean isPlural = StringExtensions.IsStringPlural( text, new CultureInfo("en"));
このIsStringPluralメソッドはStringオブジェクトで動作します(与えられたコンテキストで対象の語や句が複数形であるかどうかを判断するメソッドであると考えてください)。拡張メソッドを使用すると、同様のメソッドをクラスに関連付け、そのクラスのメンバと同じように呼び出すことができます。たとえば、StringクラスにIsPluralという拡張メソッドを作成するときには、IsStringPluralメソッド宣言の元の構文を大きく変更する必要はありません。パラメータリストにthisキーワードを追加するだけです。
public static bool IsPlural(this String text, CultureInfo cultureInfo) {/* ... */}
この拡張メソッドは、次のようにして呼び出します。
String text = "languages"; Boolean isPlural = text.IsPlural( new CultureInfo("en"));
このメソッド呼び出し構文では、読みやすさは向上しているかもしれませんが、メソッド定義元の追跡は困難になっています。IsPlural拡張メソッドを呼び出すコード行を見ても、IsPluralメソッドが実際にはStringクラスのメンバでないことはわかりませんし、このメソッドが実際にどのクラス内で宣言されているのかもわかりません。
拡張メソッドは通常の静的メソッドとまとめて扱われ、次のように使用できます。
String text = "languages"; Boolean isPlural = StringExtensions.IsPlural(text, new CultureInfo("en"));
拡張メソッドは、ラムダ式と組み合わせて、簡潔で非常に可読性の高いクエリ式を提供する目的に使用されることが期待されています。
拡張メソッドの主な難点は、名前解決の問題です。基本的にすべての拡張メソッドはグローバルで、名前も引数の数も同じメソッドは今のところ区別できません。そのため、拡張メソッドはもともとネームスペースの適切な運用を妨げる性質を持っており、現時点では、スコープを明確に区切る方法はありません。つまり、ファイルにusingステートメントを追加するだけで、コンパイルエラーが発生する可能性があります。
使用時のヒント
- 拡張メソッドは慎重に使用する。
- 拡張メソッドは固有の静的クラス内に配置する。
- 特定のクラスを拡張するすべての拡張メソッドを1つの静的クラスにまとめ、そのクラスに「<ClassName>Extensions」という名前を付ける。名前の衝突が起き、静的メソッドの呼び出し構文を使わざるを得ない場合は、最終的に可読性が低下しないようにする。
- 名前の衝突が起きる可能性を低くするため、拡張メソッドのクラスを固有のネームスペース内に保存する(名前の衝突が起きると、再び静的メソッドの呼び出しを使用せざるを得なくなる)。