はじめに
2007年12月にVisual Studioの最新バージョンであるVisual Studio 2008(以下、VS2008)がリリースされました。これと同時に.NET Frameworkの最新バージョンである.NET Framework 3.5(以下、.NET 3.5)がリリースされました。VS2008の新機能は見た目の変化や生産性の向上に分かりやすく直結する部分などが多く、大きな注目を集めていますが、.NET 3.5にもさまざまな機能強化や新機能の追加がされています。そこでVisual Studio 2008入門の第3回となる本稿では、.NET 3.5の機能強化、新機能に注目し解説していきます。
これまでの記事
対象読者
- Visual Studio 2008に興味がある方
- .NET Framework 3.5に興味がある方
必要な環境と準備
Visual Studio 2008 入門シリーズの新しい統合開発環境 Visual Studio 2008ってなんだ!?の必要な環境と準備を参考にしてください。
.NET 3.5全体像
.NET 3.5は.NET 2.0および.NET 3.0に機能追加する形で構成されています。次の図1はそのイメージを表したものです。
図1に示すように.NET 2.0の共通言語ランタイム(CLR)やベースクラスライブラリ(BCL)などのテクノロジーは.NET 3.5でも同じように利用できます。また、.NET 3.0で追加されたWPFなどの新しい4つのテクノロジーもそのまま利用できます。.NET 3.5は.NET 2.0と.NET 3.0にあるこれらのさまざまな機能を機能強化し、更にASP.NET AJAXやLINQ、言語の新機能の追加といったバージョンであると考えればよいでしょう。
本シリーズでは、.NET 3.5で機能強化された点や新機能について扱っていきます。本稿では、ベースクラスライブラリやWindows Forms、言語機能の機能強化ポイント、および.NET 3.5の目玉でもあるLINQ(Language Integrated Query:統合言語クエリ)について紹介します。
なお、以下の内容については別記事で解説します。
- ASP.NET AJAX
- Windows Presentation Foundation
- Windows Communication Foundation
- Windows Workflow Foundation
過去の.NET Frameworkとの関係
図1にも示しましたが、.NET 3.5は.NET 2.0/3.0を拡張するような形で構成されています。このため、.NET 2.0でコンパイルされたアプリケーションは基本的には.NET 3.5上でも問題なく動作します。ただし、ランタイムバージョンには以下の図2に示すような関係があります(mscorlib.dllやSystem.dllなどほとんどのBCLも同様です)。
このように.NET 2.0/3.0と.NET 3.5ではビルド番号(「メジャーバージョン.マイナーバージョン.リビジョン.ビルド」と表現する場合)に違いがあります。また、より正確には.NET 3.5は.NET 2.0/3.0を土台にしているのではなく、.NET 2.0 SP1/3.0 SP1を土台にしています。このため、よく言われる「.NET Framework 2.0でコンパイルされたアプリケーションは.NET Framework 3.5上でも動作する」は概ね正解ですが、完全ではないというところに注意が必要です。
.NET 3.5の機能強化ポイント
.NET 3.5ではベースクラスライブラリ、およびその周辺テクノロジーにさまざまな機能強化や新機能の追加がされています。ここではその中からいくつかを抜粋して紹介します。
Windowsフォームの新機能
Windowsフォームにもいくつかの新機能が追加されています。例えば、新しい統合開発環境 Visual Studio 2008ってなんだ!?の「Windowsアプリケーション開発」で紹介している内容もWindowsフォームの新機能の1つです。ここではこれとは異なるものを紹介したいと思います。
1つ目は「ファイルを開く」「ファイルを保存する」のダイアログに関するものです。従来は、実行するOSに合わせたウィンドウが表示されていました。Vistaは、Vista用の新しいタイプとXPと同様なタイプの2種類が利用できるため、これをプロパティで制御できるようになりました。具体的にはOpenFileDialog(SaveFileDialog)クラスのAutoUpgradeEnabledプロパティを設定します。初期値はtrue
で、true
の場合はVista用のもの、false
の場合はXPと同様のタイプのものを利用します。なお、XPで実行した場合この設定は無視されます。
次に、UACに関するものです。といってもただのアイコンの追加ですが、SystemIconsクラスにShieldプロパティが追加され、このプロパティからUACの管理者特権が必要ですという意味を示すアイコンを取得できます。
なお、FileDialogのAutoUpgradeEnabledプロパティおよびSystemIconsのShieldプロパティは.NET 2.0 SP1にも追加となっています。このため、SP1なしの.NET 2.0でも利用できていたような錯覚にとらわれることがありますが、実際にはこれらのプロパティを利用したコードは実行時エラーとなってしまうため、注意が必要です。
ネットワーキングの新機能
.NET 3.5ではピアツーピアネットワークの構築を容易に行えるようにするためのネットワーキング機能が追加されています。PNRP(Peer Name Resolution Protocol)を利用したピアツーピアネットワークの構築のために、System.Net.PeerToPeer名前空間が用意され、このネットワーク内で高度なコラボレーションを構築するために、System.Net.PeerToPeer.Collaboration名前空間が用意されています。いずれもSystem.Net.dll内にあり、.NET 3.5のみに提供されている機能です。
その他の新機能
これら以外にクラスライブラリとして拡充されている点を簡単に紹介しておきたいと思います。
- HashSet<T>クラス
- EventProviderクラス
- PipeClientStream クラス
- ReaderWriterLockSlimクラス
- TimeZoneInfoとDateTimeOffsetクラス
これら以外の新機能の詳細については、MSDNライブラリの.NET Framework 3.5の新機能も合わせて参照してください。
LINQ……その前に
.NETが3.5になり、合わせてVisual Basicは9.0に、C#は3.0にバージョンアップしました。これによりそれぞれの言語には、言語構文としてのさまざまな新機能が追加されています。いずれも通常のプログラミングで非常に面白く、便利に利用可能なものですので、ここで紹介しておきたいと思います。
型推論
型推論とは、実行されるコードによって変数に格納されている型をコンパイラが推論する機能です。Visual Basicでは従来から遅延バインディングという機能によって実行時に型を決定して動作する仕組みがありましたがこれとは少し意味合いが異なるものになります。以下のコードを見てください。
Dim s = "Hello!"
var s = "Hello!";
このように、VB.NETはAs句を利用しないコードを書きます。C#は型推論される型を示すvarというキーワードを利用します。この例では、「Hello!」という文字列を設定しているため、sという変数はString型として認識されます。VS2008では型推論を利用している状態のインテリセンスも問題なく利用できます(詳細はここが違う! Visual Studio 2008を参照してください)。
なお、型推論を利用すると人間が見た場合に、型が分かりにくくなるという欠点も備えることになります。むやみに型推論を利用しないようにしたり、変数名に分かりやすい名前をつけたりするなど利用上のルールが必要になります。
オブジェクト初期化子
オブジェクト初期化子とは、インスタンス生成時に同時にプロパティなどの値を設定する機能です。単純には、
オブジェクト初期化子=デフォルトコンストラクタ呼び出し+プロパティ設定
となります。オブジェクト初期化子を利用した以下のコードを見てください。
Dim cust As Customer = New Customer() With { .Name = "libaty" }
Customer cust = new Customer() { Name = "libaty" };
上記のコードは次のように分解できます(C#は割愛します)。
Dim cust As Customer = New Customer() cust.Name = "libaty"
引数付きコンストラクタを用意すればいいのではないか? と考えられる方もいるかもしれませんが、オブジェクト初期化子を利用した場合は、好きなプロパティ(フィールドも可)を自由に初期化できます。また、VS2008では、オブジェクト初期化子を利用する際にもインテリセンスのサポートを受けることができます。
匿名型
匿名型とは、予め決められた型を作成せずにインスタンスを作成する機能です。予め決められた型を作成しないため、メソッドを格納することはできず、プロパティのみを持つことができます。匿名型を利用した以下のコードを見てください。
Dim product = New With { .Name = "チョコレート", .Price = 100 }
var product = new { Name = "チョコレート", Price = 100 };
上記のコードはインスタンスを生成するNewキーワードの直後に型名がありません。このように型名を指定せず、オブジェクト初期化子を利用して生成されるクラスを匿名型と言います。匿名型はObjectクラスを直接継承したクラスですが、型名はコンパイラが自動で決定するため、変数は型推論を利用した状態で保持する必要があります。
拡張メソッド
拡張メソッドは既存クラスの派生クラスを作成することなく、既存クラスにメソッドを追加できる(ような)機能です。「ような」としているのは、事実上そのような利用ができるが、厳密には少し異なるためです。まずは拡張メソッドを定義した以下のコードを見てください。
Module StringExtensions <Extension()> _ Public Sub Print(ByVal source As String) Console.WriteLine(source) End Sub End Module
public static class StringExtensions { public static void Print(this String source) { Console.WriteLine(source) } }
Visual BasicでもC#でも静的メソッドとして構成する必要がありますが、Visual Basicの場合にはさらにExtension属性を設定する必要があります。この例では、引数としてString型を設定しているため、String型のインスタンスでPrintという新しいメソッドが利用可能となります。このように特別な静的メソッドを構成し、既存のクラスに新しいメソッドを追加するのが拡張メソッドです。VS2008ではインテリセンスで拡張メソッドを表示できるので簡単に利用することができます。
ラムダ式
ラムダ式とは、ある処理を行い、単一の結果を返却する名前を持たないメソッドを定義する機能です。このメソッドはデリゲート型として利用することができ、定義したラムダ式を変数に代入しておくことも可能です。ラムダ式を利用した場合、例えばVB.NETではAs句を利用して戻り値の型を明示的に指定することはできませんが、処理内容から戻り値の型は自動的に型推論されます。ラムダ式の記述例は以下のコードを見てください。
Dim func = Function(str As String) str = "libaty"
// 下の1行はクラス定義として定義しておく delegate bool MyFunc(string str); MyFunc func = str => str == "libaty"
この例では、String型の引数strを受け取り、引数と文字列「libaty」を比較するという処理を行うラムダ式を定義し、func変数に代入しています。これを利用する場合には、
Console.WriteLine(func("fujiko"))
とすることで利用できます(この例の場合、False
と出力されます)。このようにあるデリゲート型に対して、名前なしメソッドでインスタンスを作り、それを利用するという過程の名前なしメソッドの定義を行える機能がラムダ式になります。
LINQ
さて、型推論、オブジェクト初期化子、匿名型、拡張メソッド、ラムダ式と、Visual BasicとC#の新しい言語機能について説明してきました。これらは単独でも利用できる強力な機能ですが、これらの機能をすべて利用して記述されるのがLINQ(Language Integrated Query:統合言語クエリ)と言われる機能です。
通常、プログラミングをしている際には、オブジェクトや配列、データベース、DataSet、XMLなどさまざまな情報にアクセスする必要があります。従来は、アクセス対象に合わせてプログラミングをしていましたが、LINQを利用することで同じようなプログラミング方法で、異なる情報にアクセスできるようになります。
LINQを利用する場合には大雑把に以下の3つの手順を踏みます。
- アクセス対象のデータソースの用意
- データソースに対する抽出処理
- 抽出データの利用
アクセス対象のデータソースとしては、ArrayListなどのコレクション系オブジェクトや配列、SQL Serverデータベース、Xmlドキュメント、DataSetなどが利用可能です。これらのアクセス対象には、抽出処理をデータソースに対する処理に変換するLINQプロバイダというものが予め用意されているということでもあります。つまり、独自にLINQプロバイダを作成することで、どのようなデータソースに対してもLINQ技術を利用できるということになります。
次に、データソースに対する抽出処理です。抽出処理は一般的にクエリ式というものを使って記述されます。仮にcustomersという名前のデータソースが用意されている場合、抽出処理は次のように記述できます。
Dim query = From cust In customers _ Where cust.City = "London" _ Order By cust.Name Ascending _ Select Name = cust.Name, Phone = cust.Phone
var query = from cust in customers where cust.City == "London" orderby cust.Name ascending select new { Name = cust.Name, Phone = cust.Phone };
SQL文をご存じの場合には、順番こそ異なるものの見慣れた構文ではないかと思います。これがLINQで利用されるクエリ式と言われるものです。しかし、これはクエリ式を利用してこのようにも記述できるというだけで、実態としては次のようなコードを記述しているのと同義です。
Dim query = customers _ .Where(Function(cust) cust.City = "London") _ .OrderBy(Function(cust) cust.Name) _ .Select(Function(cust) New With { _ .Name = cust.Name, Phone = cust.Phone })
var query = customers .Where(cust => cust.City == "London") .OrderBy(cust => cust.Name) .Select(cust => new { Name = cust.Name, Phone = cust.Phone });
ここでの、Where
やOrderBy
などのメソッドはコレクション系クラスなどに対する拡張メソッドです(正確にはIEnumerable(T)インターフェースに対する拡張メソッド)。このように書き直してみると、型推論、オブジェクト初期化子、匿名型、拡張メソッド、ラムダ式のすべてを総動員している集大成の技術であることがご理解いただけるかと思います。ただ、このようなさまざまな機能を利用して書いていたのでは大変なのでこれを簡略化するためにクエリ式という新しい機能を利用して、記述を簡単にしているということになります。
最後に抽出されたデータはFor Each構文などを利用したり、WindowsフォームのDataGridViewやASP.NETのGridViewなどにそのまま利用したりといったことができます。特にASP.NETには新しいDataSourceコントロールとしてLinqDataSourceコントロールというものも用意されているので、データバインド機能の中に簡単に組み込むことができます。
まとめ
今回は.NET Framework 3.5の新機能をいろいろな点から紹介しました。全体像や前バージョンとの互換性に関する注意点を見ることで新しい.NET Frameworkが位置するところをご理解いただけたでしょうか。クラスライブラリとして、言語そのものとして、さまざまな新機能が追加されていることがわかるかと思います。
また、今回は細かい詳細の動作は説明できませんでしたが、LINQという大きな技術についてこれを支えている言語機能という点から紐解いて説明しました。少しとっつきにくいと思われる大型テクノロジーを理解する糸口になれば幸いです。
次回はクライアントサイドを中心とした.NET 3.5世代のASP.NETとWebテクノロジについて解説する予定です。どうぞお楽しみに。