.NET ROOM.NET ROOMトップへCOMRADE総合トップへ
「4:オブジェクトのシリアライズ」へ

リフレクション

 今回のコラムでは、「リフレクション」に関して説明します。
リフレクションは、ランタイム時に、型の情報を取得するための機能です。
以下に、.NET Frameworkのリフレクションによって実現可能な機能をいくつか挙げてみます。

・ランタイム時に動的に型を生成する
・ランタイム時に動的に型に関する情報を取得する
・プログラムが実行されている環境によって挙動を変化させる
(Locale情報など)


 特定のTypeを文字列で指定して、動的に取得し、そのメンバを実行する方法をリストAに示します。
このコードは、付録のReflectionTestディレクトリに収録しています。

 リストAの例では、ReflectionTestクラスはコンパイル時にはHelloクラスに関する詳細な情報を持っていません。
持っている情報は、「Helloという名前のアセンブリにあるHelloクラスには、
Printというメソッドがある」ということだけです。
ReflectionTest.csをコンパイルする際には、コンパイラはHelloクラスに関してなにも知らないため、
コード中で「Hello h = new Hello();」という記述をした場合、

「ReflectionTest.cs(6,3): error CS0246: 型または名前空間名'Hello' が見つかりませんでした。
ディレクティブを使うかアセンブリ参照を使ってください。」


というコンパイルエラーが発生し、 コンパイルできません(もちろん、コンパイル時に
「/r:Hello.dll」というオプションを付けてアセンブリをリンクすればコンパイルすることが可能です)。

リストA:リフレクションを使用した文字列による型の取得
// Hello.cs
using System;
public class Hello {
 public void Print() {
  Console.WriteLine("Hello World.");
 }
}
// ReflectionTest.cs
using System;
using System.Reflection;
public class ReflectionTest {
 static void Main() {
  Type type = Type.GetType("Hello, Hello");
  object obj = type.InvokeMember(null,
   BindingFlags.Public | BindingFlags.Instance |
   BindingFlags.CreateInstance, null, null, null);
  type.InvokeMember("Print",
   BindingFlags.Public | BindingFlags.Instance |
   BindingFlags.InvokeMethod, null, obj, null);
 }
}


 実際、VS.NETは、実行時にさまざまな型に関する情報を処理しています。
実行時にVS.NET上で処理されている型情報の典型例が「Attribute」です。
Attributeはメタデータを型やメンバなどに関連付け、それを実行時に判断して
特定の処理を行なうためのものです。

 型に対する情報の付与はインターフェイスやクラスの派生でも可能ですが、
ある型のプロパティに関連付けられるメタデータの変更は型を作成している段階では不可能です。

 また、VS.NETのコードエディタでメソッドやプロパティを入力する際の補完機能を実現するのも
リフレクションであると考えられます。
現在記述している型のメンバをリストアップして、コード入力を助けています。

 自作コントロールでリフレクションを使用すると非常に有効なケースとしては、前回の記事で書いたように、
デザイン時の挙動に関するコードを別アセンブリに分ける場合などがあります。

リフレクションを使用した文字列による型の取得の弱点

 最大の弱点は、前回簡単に触れたように、「静的リンクと違い、文字列で型を指定する場合は、
引数の文字列を間違えていてもコンパイル時にはチェックされない」という点です。
ただし、これはそもそもコンパイル時に型が判明していない場合には問題となりません。
型の取得のエラーを正しく捉えれば問題はないでしょう。

 また、前述のように、コンパイラは型の情報を詳しく把握していないため、
意図した型が取得できているかをチェックする必要があるでしょう。

 なお、リフレクションとインターフェイスを使用することで、インターフェイスによる厳密な型チェックと、
リフレクションによる型指定の柔軟性を組み合わせることができます。
コード例は、付録のReflectionAndInterfaceディレクトリに収録しています。

ReflectionTestとReflectionAndInterfaceディレクトリには、
コンパイルオプションの入力の手間を省くため、「Makefile」という名前の
ファイルを収録しています。各ディレクトリで、

C:\> nmake

としてNMAKEを実行すると、Makefileファイルであらかじめ指定してある
オプションを使用してコンパイルされます。



前へ | ページトップへ | 次へ