リフレクション (C++/CLI)Reflection (C++/CLI)

リフレクションでは、既知のデータ型を実行時に調査できます。Reflection allows known data types to be inspected at runtime. リフレクションでは、アセンブリに含まれているデータ型を列挙したり、クラス型や値型のメンバーを探索したりできます。Reflection allows the enumeration of data types in a given assembly, and the members of a given class or value type can be discovered. この処理は、コンパイル時に型が認識または参照された場合のどちらにも対応できます。This is true regardless of whether the type was known or referenced at compile time. そのため、リフレクションは、開発およびコード管理ツール向けの便利な機能です。This makes reflection a useful feature for development and code management tools.

指定されたアセンブリ名が厳密な名前に注意してください (を参照してくださいの作成と using strong-named Assemblies)、アセンブリのバージョン、カルチャ、および署名情報が含まれます。Note that the assembly name provided is the strong name (see Creating and Using Strong-Named Assemblies), which includes the assembly version, culture, and signing information. また、基底クラスの名前に加えて、データ型が定義されている名前空間の名前も取得できることに注目してください。Note also that the name of the namespace in which the data type is defined can be retrieved, along with the name of the base class.

リフレクションの機能にアクセスする最も一般的な方法は、GetType メソッドを使用することです。The most common way to access reflection features is through the GetType method. このメソッドがによって提供されるSystem.Objectからガベージ コレクションのすべてのクラスが派生します。This method is provided by System.Object, from which all garbage-collected classes derive.

注意

Microsoft で構築された .exe のリフレクションC++コンパイラは、.exe に組み込まれている場合にのみ使用できます、 /clr: 純粋なまたは /clr:safeコンパイラ オプション。Reflection on an .exe built with the Microsoft C++ compiler is only allowed if the .exe is built with the /clr:pure or /clr:safe compiler options. /Clr: 純粋な/clr:safeコンパイラ オプションは、Visual Studio 2015 で非推奨と Visual Studio 2017 では使用できません。The /clr:pure and /clr:safe compiler options are deprecated in Visual Studio 2015 and unavailable in Visual Studio 2017. 参照してください/clr (共通言語ランタイムのコンパイル)詳細についてはします。See /clr (Common Language Runtime Compilation) for more information.

詳細については、「System.Reflection」を参照してください。For more information, see System.Reflection

例:GetTypeExample: GetType

GetType メソッドは、オブジェクトが基になっている場合は型を表す Type クラス オブジェクトへのポインターを返します。The GetType method returns a pointer to a Type class object, which describes the type upon when the object is based. (、オブジェクトには、インスタンス固有の情報が含まれていない)。このメソッドで取得できる項目には、型の完全名があります。完全名は、次のように表示できます。(The Type object does not contain any instance-specific information.) One such item is the full name of the type, which can be displayed as follows:

型名には、型が定義されている完全なスコープ (名前空間も含む) が含まれています。また、.NET 構文でスコープ解決演算子としてドット (.) が付けられている点にも注意してください。Note that the type name includes the full scope in which the type is defined, including the namespace, and that it is displayed in .NET syntax, with a dot as the scope resolution operator.

// vcpp_reflection.cpp
// compile with: /clr
using namespace System;
int main() {
   String ^ s = "sample string";
   Console::WriteLine("full type name of '{0}' is '{1}'", s, s->GetType());
}
full type name of 'sample string' is 'System.String'

例: ボックス化された値の型Example: boxed value types

値型を GetType 関数で使用する場合も、最初にボックス化する必要があります。Value types can be used with the GetType function as well, but they must be boxed first.

// vcpp_reflection_2.cpp
// compile with: /clr
using namespace System;
int main() {
   Int32 i = 100;
   Object ^ o = i;
   Console::WriteLine("type of i = '{0}'", o->GetType());
}
type of i = 'System.Int32'

例: typeidExample: typeid

同様、GetTypeメソッド、 typeid演算子へのポインターを返します、オブジェクト、このコードは型名を示すためSystem.Int32します。As with the GetType method, the typeid operator returns a pointer to a Type object, so this code indicates the type name System.Int32. 型名を表示することは、リフレクションの最も基本的な機能ですが、より便利であると思われるのが、列挙型の有効な値を調査または探索できる点です。Displaying type names is the most basic feature of reflection, but a potentially more useful technique is to inspect or discover the valid values for enumerated types. これを行う静的enum::getnames関数は、テキスト形式での列挙値を含む各文字列の配列で返します。This can be done by using the static Enum::GetNames function, which returns an array of strings, each containing an enumeration value in text form. 次の例の値の列挙値を表す文字列の配列を取得する、オプション(CLR) 列挙され、ループに表示されます。The following sample retrieves an array of strings that describes the value enumeration values for the Options (CLR) enum and displays them in a loop.

4 番目のオプションを追加する場合、オプション列挙型では、このコードには、列挙体が別のアセンブリで定義されている場合でも、再コンパイルなしの新しいオプションが報告されます。If a fourth option is added to the Options enumeration, this code will report the new option without recompilation, even if the enumeration is defined in a separate assembly.

// vcpp_reflection_3.cpp
// compile with: /clr
using namespace System;

enum class Options {   // not a native enum
   Option1, Option2, Option3
};

int main() {
   array<String^>^ names = Enum::GetNames(Options::typeid);

   Console::WriteLine("there are {0} options in enum '{1}'",
               names->Length, Options::typeid);

   for (int i = 0 ; i < names->Length ; i++)
      Console::WriteLine("{0}: {1}", i, names[i]);

   Options o = Options::Option2;
   Console::WriteLine("value of 'o' is {0}", o);
}
there are 3 options in enum 'Options'
0: Option1
1: Option2
2: Option3
value of 'o' is Option2

例:GetType メンバーとプロパティExample: GetType members and properties

GetType オブジェクトは、型を調べるために使用できる多くのメンバーとプロパティをサポートします。The GetType object supports a number of members and properties that can be used to examine a type. 次のコードは、この情報の一部を取得して表示します。This code retrieves and displays some of this information:

// vcpp_reflection_4.cpp
// compile with: /clr
using namespace System;
int main() {
   Console::WriteLine("type information for 'String':");
   Type ^ t = String::typeid;

   String ^ assemblyName = t->Assembly->FullName;
   Console::WriteLine("assembly name: {0}", assemblyName);

   String ^ nameSpace = t->Namespace;
   Console::WriteLine("namespace: {0}", nameSpace);

   String ^ baseType = t->BaseType->FullName;
   Console::WriteLine("base type: {0}", baseType);

   bool isArray = t->IsArray;
   Console::WriteLine("is array: {0}", isArray);

   bool isClass = t->IsClass;
   Console::WriteLine("is class: {0}", isClass);
}
type information for 'String':
assembly name: mscorlib, Version=1.0.5000.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
namespace: System
base type: System.Object
is array: False
is class: True

型の例: 列挙型Example: enumeration of types

リフレクションを使用すると、アセンブリ内の型とクラス内のメンバーも列挙できます。Reflection also allows the enumeration of types within an assembly and the members within classes. この機能の例を示すために、次のような単純なクラスを定義します。To demonstrate this feature, define a simple class:

// vcpp_reflection_5.cpp
// compile with: /clr /LD
using namespace System;
public ref class TestClass {
   int m_i;
public:
   TestClass() {}
   void SimpleTestMember1() {}
   String ^ SimpleMember2(String ^ s) { return s; }
   int TestMember(int i) { return i; }
   property int Member {
      int get() { return m_i; }
      void set(int i) { m_i = i; }
   }
};

アセンブリの例: 検査Example: inspection of assemblies

このコードを vcpp_reflection_6.dll という DLL にコンパイルすると、リフレクションを使用してアセンブリの内容を確認できます。If the code above is compiled into a DLL called vcpp_reflection_6.dll, you can then use reflection to inspect the contents of this assembly. これは、静的リフレクション API 関数 xref:System.Reflection.Assembly.Load%2A?displayProperty=nameWithType を使用してアセンブリを読み込む必要があります。This involves using the static reflection API function xref:System.Reflection.Assembly.Load%2A?displayProperty=nameWithType to load the assembly. この関数のアドレスを返します、アセンブリモジュールと内の型について、クエリを実行できるオブジェクト。This function returns the address of an Assembly object that can then be queried about the modules and types within.

リフレクション システムが、アセンブリの配列を正常に読み込まれたらでオブジェクトを取得、Assembly.GetTypes関数。Once the reflection system successfully loads the assembly, an array of Type objects is retrieved with the Assembly.GetTypes function. 各配列要素には、異なる型の情報が含まれています。ただし、この例で定義されているクラスは 1 つだけです。Each array element contains information about a different type, although in this case, only one class is defined. ループを使用して各型のメンバーを使用してこの配列をクエリ、 :getmembers関数。Using a loop, each Type in this array is queried about the type members using the Type::GetMembers function. この関数の配列を返しますMethodInfoオブジェクト、メンバー関数は、データ メンバー、または型のプロパティに関する情報を格納している各オブジェクト。This function returns an array of MethodInfo objects, each object containing information about the member function, data member, or property in the type.

定義されているメソッドの一覧が、関数には明示的に含まれているメモTestClass関数が暗黙的に継承し、 system::objectクラス。Note that the list of methods includes the functions explicitly defined in TestClass and the functions implicitly inherited from the System::Object class. Visual C++ 構文ではなく .NET で記述されている部分では、プロパティは get 関数と set 関数でアクセスする基底のデータ メンバーとして表示されます。As part of being described in .NET rather than in Visual C++ syntax, properties appear as the underlying data member accessed by the get/set functions. get 関数と set 関数は、通常のメソッドとしてこのリストに表示されています。The get/set functions appear in this list as regular methods. リフレクションは、マイクロソフトではなく、共通言語ランタイムを通じてサポートC++コンパイラ。Reflection is supported through the common language runtime, not by the Microsoft C++ compiler.

このコードを使用すると、定義したアセンブリを調べるだけでなく、.NET アセンブリを調べることもできます。Although you used this code to inspect an assembly that you defined, you can also use this code to inspect .NET assemblies. たとえば、TestAssembly を mscorlib に置き換えると、mscorlib.dll に定義されているすべての型とメソッドのリストが表示されます。For example, if you change TestAssembly to mscorlib, then you will see a listing of every type and method defined in mscorlib.dll.

// vcpp_reflection_6.cpp
// compile with: /clr
using namespace System;
using namespace System::IO;
using namespace System::Reflection;
int main() {
   Assembly ^ a = nullptr;
   try {
      // load assembly -- do not use file extension
      // will look for .dll extension first
      // then .exe with the filename
      a = Assembly::Load("vcpp_reflection_5");
   }
   catch (FileNotFoundException ^ e) {
      Console::WriteLine(e->Message);
      return -1;
   }

   Console::WriteLine("assembly info:");
   Console::WriteLine(a->FullName);
   array<Type^>^ typeArray = a->GetTypes();

   Console::WriteLine("type info ({0} types):", typeArray->Length);

   int totalTypes = 0;
   int totalMembers = 0;
   for (int i = 0 ; i < typeArray->Length ; i++) {
      // retrieve array of member descriptions
      array<MemberInfo^>^ member = typeArray[i]->GetMembers();

      Console::WriteLine("  members of {0} ({1} members):",
      typeArray[i]->FullName, member->Length);
      for (int j = 0 ; j < member->Length ; j++) {
         Console::Write("       ({0})",
         member[j]->MemberType.ToString() );
         Console::Write("{0}  ", member[j]);
         Console::WriteLine("");
         totalMembers++;
      }
      totalTypes++;
   }
   Console::WriteLine("{0} total types, {1} total members",
   totalTypes, totalMembers);
}

方法: リフレクションを使用してプラグイン コンポーネント アーキテクチャを実装します。How to: Implement a Plug-In Component Architecture using Reflection

次のコード例では、単純な「プラグイン」アーキテクチャを実装するためにリフレクションを使用を示します。The following code examples demonstrate the use of reflection to implement a simple "plug-in" architecture. 最初のリストは、アプリケーションと、2 番目のプラグインです。The first listing is the application, and the second is the plug-in. アプリケーションは、コマンドライン引数として指定されたプラグイン DLL 内のフォーム ベースのクラスを使用して自身を設定する複数のドキュメント形式です。The application is a multiple document form that populates itself using any form-based classes found in the plug-in DLL provided as a command-line argument.

使用して、指定されたアセンブリの読み込みを試行、System.Reflection.Assembly.Loadメソッド。The application attempts to load the provided assembly using the System.Reflection.Assembly.Load method. 成功すると、アセンブリ内で型が列挙を使用して、System.Reflection.Assembly.GetTypesメソッド。If successful, the types inside the assembly are enumerated using the System.Reflection.Assembly.GetTypes method. 互換性を使用して各型をチェックしてから、System.Type.IsAssignableFromメソッド。Each type is then checked for compatibility using the System.Type.IsAssignableFrom method. この例で指定されたアセンブリ内で見つかったクラスをから派生する必要があります、Formクラスをプラグインとして修飾します。In this example, classes found in the provided assembly must be derived from the Form class to qualify as a plug-in.

互換性のあるクラスがインスタンス化し、System.Activator.CreateInstanceを受け入れ、メソッド、Typeを引数として、新しいインスタンスにポインターを返します。Compatible classes are then instantiated with the System.Activator.CreateInstance method, which accepts a Type as an argument and returns a pointer to a new instance. それぞれの新しいインスタンスは、フォームにアタッチされ、表示されます。Each new instance is then attached to the form and displayed.

なお、Loadメソッドは、ファイル拡張子を含むアセンブリ名を受け付けません。Note that the Load method does not accept assembly names that include the file extension. アプリケーションでは、メインの関数は、次のコード例は、いずれの場合も動作するように指定された拡張子をトリムします。The main function in the application trims any provided extensions, so the following code example works in either case.

Example

次のコードをプラグインを受け付けるアプリケーションを定義します。アセンブリ名は、最初の引数として指定する必要があります。The following code defines the application that accepts plug-ins. An assembly name must be provided as the first argument. このアセンブリは、少なくとも 1 つのパブリックを含める必要がありますForm派生型。This assembly should contain at least one public Form derived type.

// plugin_application.cpp
// compile with: /clr /c
#using <system.dll>
#using <system.drawing.dll>
#using <system.windows.forms.dll>

using namespace System;
using namespace System::Windows::Forms;
using namespace System::Reflection;

ref class PluggableForm : public Form  {
public:
   PluggableForm() {}
   PluggableForm(Assembly^ plugAssembly) {
      Text = "plug-in example";
      Size = Drawing::Size(400, 400);
      IsMdiContainer = true;

      array<Type^>^ types = plugAssembly->GetTypes( );
      Type^ formType = Form::typeid;

      for (int i = 0 ; i < types->Length ; i++) {
         if (formType->IsAssignableFrom(types[i])) {
            // Create an instance given the type description.
            Form^ f = dynamic_cast<Form^> (Activator::CreateInstance(types[i]));
            if (f) {
               f->Text = types[i]->ToString();
               f->MdiParent = this;
               f->Show();
            }
         }
      }
   }
};

int main() {
   Assembly^ a = Assembly::LoadFrom("plugin_application.exe");
   Application::Run(gcnew PluggableForm(a));
}

Example

次のコードから派生した 3 つのクラスを定義するFormします。The following code defines three classes derived from Form. 結果として得られるアセンブリ名の名前が前の一覧で、実行可能ファイルに渡されると、これら 3 つのクラスの各が検出され、コンパイル時に、ホスト アプリケーションに認識されているすべてがされていないことにもかかわらず、インスタンス化します。When the name of the resulting assembly name is passed to the executable in the previous listing, each of these three classes will be discovered and instantiated, despite the fact that they were all unknown to the hosting application at compile time.

// plugin_assembly.cpp
// compile with: /clr /LD
#using <system.dll>
#using <system.drawing.dll>
#using <system.windows.forms.dll>

using namespace System;
using namespace System::Windows::Forms;
using namespace System::Reflection;
using namespace System::Drawing;

public ref class BlueForm : public Form {
public:
   BlueForm() {
      BackColor = Color::Blue;
   }
};

public ref class CircleForm : public Form {
protected:
   virtual void OnPaint(PaintEventArgs^ args) override {
      args->Graphics->FillEllipse(Brushes::Green, ClientRectangle);
   }
};

public ref class StarburstForm : public Form {
public:
   StarburstForm(){
      BackColor = Color::Black;
   }
protected:
   virtual void OnPaint(PaintEventArgs^ args) override {
      Pen^ p = gcnew Pen(Color::Red, 2);
      Random^ r = gcnew Random( );
      Int32 w = ClientSize.Width;
      Int32 h = ClientSize.Height;
      for (int i=0; i<100; i++) {
         float x1 = w / 2;
         float y1 = h / 2;
         float x2 = r->Next(w);
         float y2 = r->Next(h);
         args->Graphics->DrawLine(p, x1, y1, x2, y2);
      }
   }
};

方法: リフレクションを使用してアセンブリ内のデータ型を列挙します。How to: Enumerate Data Types in Assemblies using Reflection

次の例では、パブリック型とメンバーを使用しての列挙体System.Reflectionします。The following code demonstrates the enumeration of public types and members using System.Reflection.

次のコードは、ローカル ディレクトリまたは GAC にアセンブリの名前を指定、アセンブリを開くし、説明の取得を試行します。Given the name of an assembly, either in the local directory or in the GAC, the code below attempts to open the assembly and retrieve descriptions. 成功した場合は、種類ごとに、そのパブリック メンバーが表示されます。If successful, each type is displayed with its public members.

なおSystem.Reflection.Assembly.Loadファイル拡張子が使用されていないことが必要です。Note that System.Reflection.Assembly.Load requires that no file extension is used. そのため、コマンドライン引数として"mscorlib.dll"を使用して、失敗しますだけ"mscorlib"を使用すると、.NET Framework 型の表示中。Therefore, using "mscorlib.dll" as a command-line argument will fail, while using just "mscorlib" will result the display of the .NET Framework types. アセンブリ名が指定されていない場合、コードが検出し、現在のアセンブリ内の型 (このコードから生成された EXE) を報告します。If no assembly name is provided, the code will detect and report the types within the current assembly (the EXE resulting from this code).

Example

// self_reflection.cpp
// compile with: /clr
using namespace System;
using namespace System::Reflection;
using namespace System::Collections;

public ref class ExampleType {
public:
   ExampleType() {}
   void Func() {}
};

int main() {
   String^ delimStr = " ";
   array<Char>^ delimiter = delimStr->ToCharArray( );
   array<String^>^ args = Environment::CommandLine->Split( delimiter );

// replace "self_reflection.exe" with an assembly from either the local
// directory or the GAC
   Assembly^ a = Assembly::LoadFrom("self_reflection.exe");
   Console::WriteLine(a);

   int count = 0;
   array<Type^>^ types = a->GetTypes();
   IEnumerator^ typeIter = types->GetEnumerator();

   while ( typeIter->MoveNext() ) {
      Type^ t = dynamic_cast<Type^>(typeIter->Current);
      Console::WriteLine("   {0}", t->ToString());

      array<MemberInfo^>^ members = t->GetMembers();
      IEnumerator^ memberIter = members->GetEnumerator();
      while ( memberIter->MoveNext() ) {
         MemberInfo^ mi = dynamic_cast<MemberInfo^>(memberIter->Current);
         Console::Write("      {0}", mi->ToString( ) );
         if (mi->MemberType == MemberTypes::Constructor)
            Console::Write("   (constructor)");

         Console::WriteLine();
      }
      count++;
   }
   Console::WriteLine("{0} types found", count);
}

関連項目See also