連載:C# 3.0入門第5回 拡張メソッド株式会社ピーデー 川俣 晶2008/08/08 |
|
C# 2.0プログラマーの悲劇
本題に入る前に、よくあるトラブルの事例を見てみよう。C# 3.0を使い始めたC# 2.0プログラマーの話だ。
C# 2.0プログラマーのA君が、Visual Studio 2005を用いて以下のようなコードを書いたとしよう。整数配列がすべて奇数であるかを確認し、その条件が成立していないときはその旨を出力する内容である。
| |
リスト1 C# 2.0によるコードその1 |
しかし、foreach文でループするのはあまりエレガントではない。そこで、ある条件を満たさない項目が存在することを示すだけなら、条件に当てはまらないものを探せばよいことに気付いた。
最初に思い付いたのはArray.Findメソッドを使う方法だ。しかし、Array.Findメソッドは項目が見つからないときに、その型の既定の値を返す。つまり、int型なら0を返す。しかしこれでは、0を発見したのか、発見できずに0になったのか分からない。
結局、A君は値ではなく、インデックスを返すFindIndexメソッドを使ってリスト1を書き直した。
| |
リスト2 C# 2.0によるコードその2 |
しかし、このコードにもA君は不満を持っていた。本来「すべての値が奇数である」ことを確認するプログラムだが、実際にソース・コードに書かれているのは、「偶数の値を探す」処理だからだ。
さて、A君はC# 3.0で配列(=Arrayクラス)に新しいメソッド“All”が追加されたことを知った。Allメソッドとは、「シーケンスのすべての要素が条件を満たしているかどうかを判断」するものであり、まさに「すべての値が奇数である」という意図を示すにふさわしいメソッドに思えた。
そこで、A君は以下のようなプログラムをVisual Studio 2008で書いて、Allメソッドの挙動を確認した。
| |
リスト3 C# 3.0でAllメソッドを試す |
これを見て、A君は「まさに求めていたメソッドだ」と確信した。そして、さっそくVisual Studio 2005で開発してきたリスト1のコードをVisual Studio 2008で読み込み、プロジェクトのプロパティで「対象のフレームワーク」を.NET Framework 3.5に変更した。これでAllメソッドが使用できるはずである。
A君はソース・コードの変更に着手した。しかし、A君はすぐにおかしなことに気付く。配列primesに対してIntelliSense(インテリセンス)を機能させても、Allメソッドがリストされないのだ。A君はおかしいと思いつつ、手動で以下のように書き換えた。ところがコンパイル・エラーとなる。
| |
リスト4 コンパイル不能となったリスト1からの改良コード |
このエラー・メッセージを見て、A君はろうばいした。
「'System.Array' に 'All' の定義が含まれていない」だって? そんなバカな。だって、さっき書いたテスト用のソース(リスト3)はOKだったし、対象となるフレームワークのバージョンも正しく切り替えたはずだ。配列に対するメソッド呼び出しは、System.Arrayクラスのメソッドが使われるはずじゃないのか!?
これに対する答えは、少々ややこしい。
まず、A君の以下の認識は正しい。
- Allメソッドは.NET Framework 3.5で拡張されたメソッドである
- Allメソッドを使用するには、対象のフレームワークに.NET Framework 3.5を指定しなければならない(.NET Framework 2.0では使えない)
- Allメソッドは配列(System.Arrayクラス)に対して拡張されたメソッドである
しかし、以下の認識は正しくない。
- AllメソッドはSystem.Arrayクラスのメソッドである
C# 3.0には、既存のクラスを変更せずに、メソッドを追加する機能が付加されている。Allメソッドは、この機能を用いて配列に対して拡張されたメソッドである。.NET Framework 3.5になってSystem.Arrayクラスそのものにメソッドが増えたわけではない。しかし、呼び出し可能なメソッドは増えている。このようなメソッドを「拡張メソッド(Extension methods)」と呼ぶ。
そして、拡張メソッドを使うためには下準備が必要になる。それを有効にするために、「スイッチを入れる」必要があるのだ。A君のプログラムがコンパイルできなかったのは、「スイッチ」が入っていなかったからである。
以下の1行をソース・コードの先頭に追加すればそのスイッチがオンになり、Allメソッドは使用できるようになる。
| |
Allメソッドを利用するのに必要な記述 |
しかし、C# 2.0にどっぷり漬かったプログラマーに対して、これはあまりに難題だ。なぜかといえば、usingキーワードとはC# 1.0から存在する当たり前の機能であり、名前の短縮形を与えるために使われるだけだった。使用できる機能をオン/オフする役割など持っていなかったはずだ。それが「スイッチ」としての機能を持つなど、容易には想像できないだろう。
しかも、この1行は、Visual Studio 2008で自動的に記述されているため、その重要性に気付きにくい。しかし、これを含まないVisual Studio 2005のソース・コードを持ち込めば、即座に凶悪な牙をむくわけである。
今回は、この強力だが難解な拡張メソッドを使いこなせるようになろう。分かってしまえば何ら難しいものではない。
INDEX | ||
C# 3.0入門 | ||
第5回 拡張メソッド | ||
1.C# 2.0プログラマーの悲劇 | ||
2.拡張メソッドの概要/スイッチなしで機能する例/sealedクラスを拡張する | ||
3.メソッド呼び出しと型の関係/thisの正体/拡張メソッドを使用すべきとき | ||
「C# 3.0入門」 |
- 第2回 簡潔なコーディングのために (2017/7/26)
ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている - 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう - 第1回 明瞭なコーディングのために (2017/7/19)
C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える - Presentation Translator (2017/7/18)
Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|