2014-11-12T01:03:53の更新内容

programming/netfx/reflection/index.wiki.txt

current previous
1,3388 0,0
+
${smdncms:title,リフレクション}
+
${smdncms:header_title,リフレクション (System.Reflection)}
+
${smdncms:keywords,リフレクション,メタデータ,動的生成,型情報}
+
${smdncms:document_versions,codelang=cs,codelang=vb}
+

          
+
reflectionという英単語には「反射」や「反響」といった意味、また「内省」や「熟考」などの自分自身を見つめるといった意味があります。 「自己言及」と訳される場合もあります。 プログラミングにおけるリフレクションとは、プログラムのメタデータ(=型情報などプログラム自身に埋め込まれている情報)を取得することを指します。
+

          
+
.NET Frameworkではプログラム(モジュール)に様々なメタデータが埋め込まれます。 リフレクションによってこれらを利用することにより、型情報や[[属性>programming/netfx/attributes]]の取得、型情報からのインスタンスの作成、遅延バインディング、アセンブリの動的読み込み・生成など、さまざまなことが行えるようになっています。 文字列で名前を指定して呼び出すメソッドや使用する型を選択するといった手法もリフレクションによって実装することができます。
+

          
+
#adunit
+

          
+
-関連するページ
+
--[[programming/netfx/attributes]]
+
--[[programming/netfx/serialization]]
+
--[[programming/netfx/embeddedresource]]
+
--[[programming/netfx/debugging]]
+
--[[programming/netfx/classlibrary/1_interoperability]]
+
--[[programming/netfx/tips/get_assembly_version_info]]
+
--[[programming/netfx/tips/get_delegate_signature_from_type]]
+
--[[programming/netfx/tips/set_struct_field_using_reflection]]
+
--[[programming/netfx/tips/check_type_isassignablefrom_issubclassof]]
+
--[[programming/netfx/environment/1_process#ProcessAndAssembly]]
+

          
+
*リフレクションの例
+

          
+
**型情報の取得
+
リフレクションによって実行時に型自身の情報を取得することができます。 取得できる情報については後述の[[#type_informations]]や[[#Type.GetMembers]]などで解説します。
+

          
+

          
+
#tabpage(codelang=cs,container-title=実行時に型情報を取得する)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class Account {
+
  public int ID { get; set; }
+
  public string Name { get; set; }
+

          
+
  public Account(int id, string name)
+
  {
+
    this.ID = id;
+
    this.Name = name;
+
  }
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    // Accountクラスの型情報を取得する
+
    Type t = typeof(Account);
+

          
+
    Console.WriteLine("Name = {0}", t.Name);
+
    Console.WriteLine("BaseType = {0}", t.BaseType);
+

          
+
    // Accountクラスのすべてのメンバ情報を取得する
+
    // (パブリックおよび非パブリックのインスタンスメンバを取得する)
+
    MemberInfo[] members = t.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
+

          
+
    foreach (MemberInfo m in members) {
+
      Console.WriteLine("MemberType = {0}, Name = {1}", m.MemberType, m.Name);
+
    }
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class Account
+
  Public Property ID As Integer
+
  Public Property Name As String
+

          
+
  Public Sub New(ByVal id As Integer, ByVal name As String)
+
    Me.ID = id
+
    Me.Name = name
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ' Accountクラスの型情報を取得する
+
    Dim t As Type = GetType(Account)
+

          
+
    Console.WriteLine("Name = {0}", t.Name)
+
    Console.WriteLine("BaseType = {0}", t.BaseType)
+

          
+
    ' Accountクラスのすべてのメンバ情報を取得する
+
    ' (パブリックおよび非パブリックのインスタンスメンバを取得する)
+
    Dim members() As MemberInfo = t.GetMembers(BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.Instance)
+

          
+
    For Each m As MemberInfo In members
+
      Console.WriteLine("MemberType = {0}, Name = {1}", m.MemberType, m.Name)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果例){{
+
Name = Account
+
BaseType = System.Object
+
MemberType = Method, Name = get_ID
+
MemberType = Method, Name = set_ID
+
MemberType = Method, Name = get_Name
+
MemberType = Method, Name = set_Name
+
MemberType = Method, Name = Equals
+
MemberType = Method, Name = Finalize
+
MemberType = Method, Name = GetHashCode
+
MemberType = Method, Name = GetType
+
MemberType = Method, Name = MemberwiseClone
+
MemberType = Method, Name = ToString
+
MemberType = Method, Name = obj_address
+
MemberType = Constructor, Name = .ctor
+
MemberType = Property, Name = ID
+
MemberType = Property, Name = Name
+
MemberType = Field, Name = <ID>k__BackingField
+
MemberType = Field, Name = <Name>k__BackingField
+
}}
+

          
+
**インスタンスの操作
+
リフレクション機能を使うと、取得した型情報を使ってメソッドの呼び出しやフィールドの取得・設定などのインスタンスの操作をすることができます。 これにより、型に依存しない汎用的な処理を記述したり、実行時まで型が決定していないインスタンスに対する操作を行うといったことができます。
+

          
+
#tabpage(codelang=cs,container-title=リフレクション機能を使ってインスタンスの生成・操作を行う)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class Account {
+
  public string Name { get; set; }
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    // クラス名Accountの型情報を取得する
+
    Type t = Type.GetType("Account");
+

          
+
    // 型情報からインスタンスを作成する
+
    object inst = Activator.CreateInstance(t);
+

          
+
    // Nameプロパティを取得する
+
    PropertyInfo p = t.GetProperty("Name");
+

          
+
    // プロパティに値を設定する
+
    p.SetValue(inst, "Alice", null);
+

          
+
    // プロパティの値を取得して表示する
+
    Console.WriteLine("Name = {0}", p.GetValue(inst, null));
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class Account
+
  Public Property Name As String
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ' クラス名Accountの型情報を取得する
+
    Dim t As Type = Type.GetType("Account")
+

          
+
    ' 型情報からインスタンスを作成する
+
    Dim inst As Object = Activator.CreateInstance(t)
+

          
+
    ' Nameプロパティを取得する
+
    Dim p As PropertyInfo = t.GetProperty("Name")
+

          
+
    ' プロパティに値を設定する
+
    p.SetValue(inst, "Alice", Nothing)
+

          
+
    ' プロパティの値を取得して表示する
+
    Console.WriteLine("Name = {0}", p.GetValue(inst, Nothing))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Name = Alice
+
}}
+

          
+
このような操作については[[#invoke_member]]で解説します。
+

          
+
**属性
+
型情報以外のメタデータして''属性''が挙げられます。 .NET Frameworkでは属性を使うことでプログラムにメタデータを埋め込むことができ、それを実行時に取得・参照することができます。 属性にはコンパイラ・ランタイムが特別な操作を行うために使用されるものが存在するほか、独自に意味を定義して情報を埋め込む''カスタム属性''があります。
+

          
+
#tabpage(codelang=cs,container-title=カスタム属性によるメタデータの埋め込みと取得)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
// カスタム属性となるクラス
+
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+
public class AuthorAttribute : Attribute {
+
  public string Name {
+
    get; private set;
+
  }
+

          
+
  public string Version;
+

          
+
  public AuthorAttribute(string name)
+
  {
+
    this.Name = name;
+
  }
+
}
+

          
+
class Sample {
+
  // カスタム属性が設定されたメソッド
+
  [Author("Alice", Version = "1.0")]
+
  [Author("Bob", Version = "1.1")]
+
  [Author("Charlie", Version = "1.2")]
+
  public static void TestMethod()
+
  {
+
  }
+

          
+
  public static void Main()
+
  {
+
    // メソッドの情報を取得する
+
    MethodInfo method = typeof(Sample).GetMethod("TestMethod");
+

          
+
    // メソッドに設定されているカスタム属性を取得して列挙する
+
    foreach (AuthorAttribute attr in method.GetCustomAttributes(typeof(AuthorAttribute), false)) {
+
      // 属性に設定されている値を表示する
+
      Console.WriteLine("Author: {0}, Version: {1}", attr.Name, attr.Version);
+
    }
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
' カスタム属性となるクラス
+
<AttributeUsage(AttributeTargets.Method, AllowMultiple := True)> _
+
Public Class AuthorAttribute
+
  Inherits Attribute
+

          
+
  Private _name As String
+

          
+
  Public Property Name As String
+
    Get
+
      Return _name
+
    End Get
+
    Set(ByVal value As String)
+
      _name = value
+
    End Set
+
  End Property
+

          
+
  Public Version As String
+

          
+
  Public Sub New(ByVal name As String)
+
    Me._name = name
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  ' カスタム属性が設定されたメソッド
+
  <Author("Alice", Version := "1.0")> _
+
  <Author("Bob", Version := "1.1")> _
+
  <Author("Charlie", Version := "1.2")> _
+
  Public Shared Sub TestMethod()
+
  End Sub
+

          
+
  Public Shared Sub Main()
+
    ' メソッドの情報を取得する
+
    Dim method As MethodInfo = GetType(Sample).GetMethod("TestMethod")
+

          
+
    ' メソッドに設定されているカスタム属性を取得して列挙する
+
    For Each attr As AuthorAttribute In method.GetCustomAttributes(GetType(AuthorAttribute), False)
+
      ' 属性に設定されている値を表示する
+
      Console.WriteLine("Author: {0}, Version: {1}", attr.Name, attr.Version)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果例){{
+
Author: Charlie, Version: 1.2
+
Author: Bob, Version: 1.1
+
Author: Alice, Version: 1.0
+
}}
+

          
+
属性について、および属性の使用方法などについて詳しくは[[programming/netfx/attributes]]で個別に解説しています。
+

          
+
**リソース
+
型情報や属性のほかに、リソースもメタデータとして埋め込まれます。 リフレクションによってEXEやDLLに埋め込まれているリソースを利用することもできます。
+

          
+
リフレクションを使ったリソースの扱い方については[[programming/netfx/embeddedresource]]で個別に解説しています。
+

          
+

          
+
*型情報 (Typeクラス) [#System.Type]
+
リフレクションにおいて中心的な役割を果たす&msdn(netfx,type,System.Type){Typeクラス};について解説します。 このクラスは型情報を扱うクラスとなっていて、このクラスから型自体の情報を取得できるほか、メソッドやフィールドなどメンバの情報の取得、型情報からのインスタンスの生成や、メソッド呼び出し・フィールドの書き換えなどのインスタンスの操作を行う上で必要な情報を取得することができます。
+

          
+
**Typeクラスの取得 (typeof, GetType)
+
C#では``typeof``演算子、VBでは``GetType``演算子を使うことで型情報をTypeクラスのインスタンスとして取得することができます。 また&msdn(netfx,member,System.Object.GetType){GetTypeメソッド};を呼び出すことによっても取得することができます。 このメソッドは&msdn(netfx,type,System.Object){Objectクラス};から継承されるため、どの型でも共通して使用することができます。 型名から直接型情報を取得したい場合には``typeof``/``GetType``、インスタンスからその型の型情報を取得したい場合には``GetType``メソッドを使用します。
+

          
+
#tabpage(codelang=cs,container-title=型情報の取得)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    Type t1 = typeof(int); // int型の型情報の取得
+
    Type t2 = typeof(Sample); // Sampleクラスの型情報の取得
+

          
+
    string str = "foo";
+

          
+
    Type t3 = str.GetType(); // stringインスタンスからの型情報の取得
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t1 As Type = GetType(Integer) ' Integer型の型情報の取得
+
    Dim t2 As Type = GetType(Sample) ' Sampleクラスの型情報の取得
+

          
+
    Dim str As String = "foo"
+

          
+
    Dim t3 As Type = str.GetType() ' Stringインスタンスからの型情報の取得
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
***ジェネリック型の型情報
+
たとえば[[List<T>クラス>programming/netfx/collections/2_generic_1_list]]を例にとった場合、型引数``T``の型が具体的に定まっていない``List<T>``を特に''オープンジェネリック型''、対して``List<int>``や``List<string>``など型引数``T``の型が具体的な型が定まっているものを''クローズジェネリック型''(あるいは''構築ジェネリック型''、''構築された型'')と呼びます。
+

          
+
``typeof``演算子・``GetType``演算子でジェネリック型の型情報を取得する場合、オープンジェネリック型とクローズジェネリック型を区別して取得することができます。 オープンジェネリック型を表す場合は型パラメータの指定を省略した型名(例:``Dictionary<,>``/``Dictionary(Of ,)``)を使用し、一方クローズジェネリック型では具体的な型名を指定した型名(例:``Dictionary<string, int>``/``Dictionary(Of String, Integer)``)を使用することによってそれぞれの型情報を取得することができます。
+

          
+

          
+
#tabpage(codelang=cs,container-title=ジェネリック型の型情報の取得)
+
#code{{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    Type t1 = typeof(List<>); // 型パラメータが1つのオープンジェネリック型
+
    Type t2 = typeof(List<int>); // 型パラメータが1つのクローズジェネリック型
+
    Type t3 = typeof(List<string>);
+

          
+
    Console.WriteLine(t1);
+
    Console.WriteLine(t2);
+
    Console.WriteLine(t3);
+

          
+
    Type t4 = typeof(Dictionary<,>); // 型パラメータが2つのオープンジェネリック型
+
    Type t5 = typeof(Dictionary<string, int>); // 型パラメータが2つのクローズジェネリック型
+

          
+
    Console.WriteLine(t4);
+
    Console.WriteLine(t5);
+

          
+
    Type t6 = typeof(Action<,>);
+
    Type t7 = typeof(Action<,,>);
+
    Type t8 = typeof(Action<,,,>);
+

          
+
    Console.WriteLine(t6);
+
    Console.WriteLine(t7);
+
    Console.WriteLine(t8);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t1 As Type = GetType(List(Of)) ' 型パラメータが1つのオープンジェネリック型
+
    Dim t2 As Type = GetType(List(Of Integer)) ' 型パラメータが1つのクローズジェネリック型
+
    Dim t3 As Type = GetType(List(Of String))
+

          
+
    Console.WriteLine(t1)
+
    Console.WriteLine(t2)
+
    Console.WriteLine(t3)
+

          
+
    Dim t4 As Type = GetType(Dictionary(Of ,)) ' 型パラメータが2つのオープンジェネリック型
+
    Dim t5 As Type = GetType(Dictionary(Of String, Integer)) ' 型パラメータが2つのクローズジェネリック型
+

          
+
    Console.WriteLine(t4)
+
    Console.WriteLine(t5)
+

          
+
    Dim t6 As Type = GetType(Action(Of ,))
+
    Dim t7 As Type = GetType(Action(Of ,,))
+
    Dim t8 As Type = GetType(Action(Of ,,,))
+

          
+
    Console.WriteLine(t6)
+
    Console.WriteLine(t7)
+
    Console.WriteLine(t8)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
System.Collections.Generic.List`1[T]
+
System.Collections.Generic.List`1[System.Int32]
+
System.Collections.Generic.List`1[System.String]
+
System.Collections.Generic.Dictionary`2[TKey,TValue]
+
System.Collections.Generic.Dictionary`2[System.String,System.Int32]
+
System.Action`2[T1,T2]
+
System.Action`3[T1,T2,T3]
+
System.Action`4[T1,T2,T3,T4]
+
}}
+

          
+
&msdn(netfx,member,System.Type.MakeGenericType){Type.MakeGenericTypeメソッド};を使用するとオープンジェネリック型(ジェネリック型定義)の型情報からクローズジェネリック型(構築ジェネリック型)を取得することができます。 例えば``Dictionary<,>``の型情報から``Dictionary<string, int>``の型情報を取得したい場合は次のようにします。
+

          
+
#tabpage(codelang=cs,container-title=クローズジェネリック型の取得)
+
#code{{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    Type t1 = typeof(Dictionary<,>); // オープンジェネリック型
+

          
+
    Console.WriteLine(t1);
+

          
+
    // Dictionary<,>からDictionary<string, int>の型情報を作成する
+
    Type t2 = t1.MakeGenericType(typeof(string), typeof(int));
+

          
+
    Console.WriteLine(t2);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t1 As Type = GetType(Dictionary(Of ,)) ' オープンジェネリック型
+

          
+
    Console.WriteLine(t1)
+

          
+
    ' Dictionary(Of ,)からDictionary(Of String, Integer)の型情報を作成する
+
    Dim t2 As Type = t1.MakeGenericType(GetType(String), GetType(Integer))
+

          
+
    Console.WriteLine(t2)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
System.Collections.Generic.Dictionary`2[TKey,TValue]
+
System.Collections.Generic.Dictionary`2[System.String,System.Int32]
+
}}
+

          
+
逆に&msdn(netfx,member,System.Type.GetGenericTypeDefinition){GetGenericTypeDefinitionメソッド};ではクローズジェネリック型の型情報からオープンジェネリック型の型情報を取得することができます。
+

          
+
#tabpage(codelang=cs,container-title=オープンジェネリック型の取得)
+
#code{{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    Type t1 = typeof(Dictionary<string, int>); // クローズジェネリック型
+

          
+
    Console.WriteLine(t1);
+

          
+
    // Dictionary<string, int>からDictionary<,>の型情報を作成する
+
    Type t2 = t1.GetGenericTypeDefinition();
+

          
+
    Console.WriteLine(t2);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t1 As Type = GetType(Dictionary(Of String, Integer)) ' クローズジェネリック型
+

          
+
    Console.WriteLine(t1)
+

          
+
    ' Dictionary(Of String, Integer)からDictionary(Of ,)の型情報を作成する
+
    Dim t2 As Type = t1.GetGenericTypeDefinition()
+

          
+
    Console.WriteLine(t2)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
System.Collections.Generic.Dictionary`2[System.String,System.Int32]
+
System.Collections.Generic.Dictionary`2[TKey,TValue]
+
}}
+

          
+
また.NET Frameworkでは、ジェネリック型の型パラメータ(例えば``List<T>``の``T``)もTypeクラスとして扱います。 詳しくは後述の[[#Type.GetGenericArguments]]で解説します。
+

          
+

          
+
****ジェネリック型と型名の表記
+
Typeクラスなどで使われる型名の多くはコード上での表記と変わりませんが、ジェネリック型では異なる表記が使われます。 例えばコード上では``List<T>``/``List(Of T)``と記述される型には``System.Collections.Generic.List`1``といった表記が使われます。 型名では山括弧``< >``で型パラメータ名を記述する代わりに、バッククオート`````の後ろに''型パラメータの数''が記述されます。 ``Dictionary<TKey, TValue>``では型パラメータの数が2つとなるため、``System.Collections.Generic.Dictionary`2``となります。
+

          
+
#tabpage(codelang=cs,container-title=ジェネリック型名の表記)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    Console.WriteLine(typeof(System.Collections.Generic.List<>));
+
    Console.WriteLine(typeof(System.Collections.Generic.List<int>));
+
    Console.WriteLine(typeof(System.Collections.Generic.Dictionary<,>));
+

          
+
    Console.WriteLine(typeof(System.Action));
+
    Console.WriteLine(typeof(System.Action<>));
+
    Console.WriteLine(typeof(System.Action<,>));
+
    Console.WriteLine(typeof(System.Action<,,>));
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Console.WriteLine(GetType(System.Collections.Generic.List(Of )))
+
    Console.WriteLine(GetType(System.Collections.Generic.List(Of Integer)))
+
    Console.WriteLine(GetType(System.Collections.Generic.Dictionary(Of ,)))
+

          
+
    Console.WriteLine(GetType(System.Action))
+
    Console.WriteLine(GetType(System.Action(Of )))
+
    Console.WriteLine(GetType(System.Action(Of ,)))
+
    Console.WriteLine(GetType(System.Action(Of ,,)))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
System.Collections.Generic.List`1[T]
+
System.Collections.Generic.List`1[System.Int32]
+
System.Collections.Generic.Dictionary`2[TKey,TValue]
+
System.Action
+
System.Action`1[T]
+
System.Action`2[T1,T2]
+
System.Action`3[T1,T2,T3]
+
}}
+

          
+
文字列形式で型名を指定する場合にはこの表記を使用する必要があります。
+

          
+
-関連: [[programming/netfx/classlibrary/2_xmldoccomments#xmlelement_memberid]]
+

          
+
**アセンブリからの型情報の取得
+
''アセンブリ''とは何かを簡略に説明すると、EXEファイルあるはDLLファイルから読み込まれた実行可能コードとメタデータのセットのことです。 (より正確には、実行可能コードとメタデータのセットである''モジュール''を格納したもの) 特定のEXEやDLLで定義されている型情報を取得したい場合には、まず次のようなメソッドによってアセンブリを取得する必要があります。
+

          
+
|*アセンブリを取得するためのメソッド
+
|~メソッド|~概要|h
+
|&msdn(netfx,member,System.Reflection.Assembly.GetAssembly){Assembly.GetAssembly};|指定された型が宣言されているアセンブリを取得する|
+
|&msdn(netfx,member,System.Reflection.Assembly.GetExecutingAssembly){Assembly.GetExecutingAssembly};|現在実行中のコードが存在するアセンブリを取得する|
+
|&msdn(netfx,member,System.Reflection.Assembly.GetCallingAssembly){Assembly.GetCallingAssembly};|現在実行中のコードを呼び出したアセンブリを取得する|
+
|&msdn(netfx,member,System.Reflection.Assembly.GetEntryAssembly){Assembly.GetEntryAssembly};|プロセスのエントリーポイントを含むアセンブリを取得する|
+
|&msdn(netfx,member,System.Reflection.Assembly.Load){Assembly.Load};|アセンブリを読み込んで取得する
+
|&msdn(netfx,member,System.Reflection.Assembly.ReflectionOnlyLoad){Assembly.ReflectionOnlyLoad};|リフレクションのみを目的としてアセンブリを読み込み、取得する|
+

          
+
文字列で表された型名から型情報を取得したい場合は&msdn(netfx,member,System.Reflection.Assembly.GetType){Assembly.GetTypeメソッド};を使用します。 次の例では現在実行しているアセンブリから指定された名前の型情報を取得しています。 GetTypeメソッドに指定する型名は名前空間を含めた''完全名''を指定する必要があります。
+

          
+
#tabpage(codelang=cs,container-title=文字列で表された型名から型情報を取得する)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
namespace NS {
+
  class T1 {}
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    // 現在実行しているコードが含まれるアセンブリを取得する
+
    Assembly a = Assembly.GetExecutingAssembly();
+

          
+
    // NS名前空間のクラスT1の型情報を取得する
+
    Type t = a.GetType("NS.T1");
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Namespace NS
+
  Class T1
+
  End Class
+
End Namespace
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ' 現在実行しているコードが含まれるアセンブリを取得する
+
    Dim a As [Assembly] = [Assembly].GetExecutingAssembly()
+

          
+
    ' NS名前空間のクラスT1の型情報を取得する
+
    Dim t As Type = a.GetType("NS.T1")
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
また入れ子になっている型の型情報を取得したい場合は、目的の型を含んでいる型名と入れ子になっている型の名前を``+``で連結した型名を指定します。
+

          
+
#tabpage(codelang=cs,container-title=入れ子になっている型の型情報を取得する)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
namespace NS {
+
  class ContainerClass {
+
    class InnerClass {
+
    }
+
  }
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    Assembly a = Assembly.GetExecutingAssembly();
+

          
+
    // 入れ子になっているクラスInnerClassの型情報を取得する
+
    Type t = a.GetType("NS.ContainerClass+InnerClass");
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Namespace NS
+
  Class ContainerClass
+
    Class InnerClass
+
    End Class
+
  End Class
+
End Namespace
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim a As [Assembly] = [Assembly].GetExecutingAssembly()
+

          
+
    ' 入れ子になっているクラスInnerClassの型情報を取得する
+
    Dim t As Type = a.GetType("NS.ContainerClass.InnerClass")
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
アセンブリに定義されているすべての型情報を取得したい場合は&msdn(netfx,member,System.Reflection.Assembly.GetTypes){Assembly.GetTypesメソッド};あるいは&msdn(netfx,member,System.Reflection.Assembly.GetExportedTypes){Assembly.GetExportedTypesメソッド};を使用します。 GetTypesメソッドではアセンブリに含まれるすべての型が返されるのに対して、GetExportedTypesメソッドではアセンブリの外部から参照できる型のみが返されます。
+

          
+
#tabpage(codelang=cs,container-title=アセンブリ内のすべての型情報の取得)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
public class T1 {} // アセンブリ外に公開されるクラス
+
internal class T2 {}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    Assembly a = Assembly.GetExecutingAssembly();
+

          
+
    Console.WriteLine("[GetTypes]");
+

          
+
    foreach (var t in a.GetTypes()) {
+
      Console.WriteLine(t);
+
    }
+

          
+
    Console.WriteLine("[GetExportedTypes]");
+

          
+
    foreach (var t in a.GetExportedTypes()) {
+
      Console.WriteLine(t);
+
    }
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Public Class T1 : End Class ' アセンブリ外に公開されるクラス
+
Friend Class T2 : End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim a As [Assembly] = [Assembly].GetExecutingAssembly()
+

          
+
    Console.WriteLine("[GetTypes]")
+

          
+
    For Each t As Type In a.GetTypes()
+
      Console.WriteLine(t)
+
    Next
+

          
+
    Console.WriteLine("[GetExportedTypes]")
+

          
+
    For Each t As Type In a.GetExportedTypes()
+
      Console.WriteLine(t)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
[GetTypes]
+
T1
+
T2
+
Sample
+
[GetExportedTypes]
+
T1
+
}}
+

          
+

          
+
**Typeクラスから取得できる情報 [#type_informations]
+
Typeクラスからは型名だけでなく、型がクラスなのかインターフェイスなのかといった型の種類や特徴に関する情報や、型で定義されているメソッド・プロパティ・フィールドなどに関する情報を取得することができます。
+

          
+
***型情報の参照
+
Typeクラスでは次のようなプロパティによって型の種類に関する情報を参照・取得することができます。
+

          
+
|*Typeクラスのプロパティ
+
|>|~プロパティ|~意味|h
+
|~型の名称|&msdn(netfx,member,System.Type.Name){Name};|名前空間を含まない型名&br;(例:``System.IO.Stream``なら``Stream``)|
+
|~|&msdn(netfx,member,System.Type.Namespace){Namespace};|名前空間&br;(例:``System.IO.Stream``なら``System.IO``)|
+
|~|&msdn(netfx,member,System.Type.FullName){FullName};|名前空間を含む型名&br;(例:``System.IO.Stream``なら``System.IO.Stream``)|
+
|~型の宣言箇所|&msdn(netfx,member,System.Type.Assembly){Assembly};|型が宣言されているアセンブリ|
+
|~|&msdn(netfx,member,System.Type.Module){Module};|型が宣言されているモジュール|
+
|~|&msdn(netfx,member,System.Type.DeclaringType){DeclaringType};|入れ子になっている型の場合、その型を含んでいる型|
+
|~型の分類|&msdn(netfx,member,System.Type.IsClass){IsClass};|型がクラス型かどうか|
+
|~|&msdn(netfx,member,System.Type.IsValueType){IsValueType};|型が値型(構造体・列挙体・プリミティブ数値型など)かどうか (関連:[[programming/netfx/valuetype_referencetype]])|
+
|~|&msdn(netfx,member,System.Type.IsInterface){IsInterface};|型がインターフェイス型かどうか|
+
|~|&msdn(netfx,member,System.Type.IsEnum){IsEnum};|型が列挙体かどうか|
+
|~|&msdn(netfx,member,System.Type.IsArray){IsArray};|型が配列型かどうか|
+
|~|&msdn(netfx,member,System.Type.IsPrimitive){IsPrimitive};|型がプリミティブ型かどうか (関連:[[programming/netfx/basic_types/0_characteristics]])|
+
|~型の属性・状態・継承関係|&msdn(netfx,member,System.Type.IsAbstract){IsAbstract};|型が抽象型(``abstract``/``MustInherit``)かどうか|
+
|~|&msdn(netfx,member,System.Type.IsSealed){IsSealed};|型がシールクラス(``sealed``/``NotInheritable``)かどうか|
+
|~|&msdn(netfx,member,System.Type.IsPublic){IsPublic};|型がパブリックかどうか|
+
|~|&msdn(netfx,member,System.Type.IsNotPublic){IsNotPublic};|型が非パブリックかどうか|
+
|~|&msdn(netfx,member,System.Type.IsNested){IsNested};|型が入れ子になっているか(他の型の内部で宣言されているか)|
+
|~|&msdn(netfx,member,System.Type.BaseType){BaseType};|基底クラス(継承元)の型情報|
+
|~ジェネリック型|&msdn(netfx,member,System.Type.IsGenericType){IsGenericType};|ジェネリック型かどうか&br;(オープン型``List<>``とクローズ型``List<int>``のどちらでもtrueとなる)|
+
|~|&msdn(netfx,member,System.Type.IsGenericTypeDefinition){IsGenericTypeDefinition};|ジェネリック型定義(オープンジェネリック型)かどうか&br;(オープン型``List<>``ではtrue、クローズ型``List<int>``ではfalseとなる)|
+
|~|&msdn(netfx,member,System.Type.IsConstructedGenericType){IsConstructedGenericType};|構築ジェネリック型(クローズジェネリック型)かどうか&br;(オープン型``List<>``ではfalse、クローズ型``List<int>``ではtrueとなる)|
+
|~|&msdn(netfx,member,System.Type.ContainsGenericParameters){ContainsGenericParameters};|具体的な型が指定されていない型パラメーターを含むかどうか&br;(``List<>``ではtrue、``List<int>``ではfalseとなる&br;同様に``Dictionary<,>.KeyCollection``ではtrue、``Dictionary<int,int>.KeyCollection``ではfalseとなる)|
+
|~|&msdn(netfx,member,System.Type.IsGenericParameter){IsGenericParameter};|型がジェネリック型パラメータを表すかどうか|
+
|>|~プロパティ|~意味|f
+

          
+
次の例はTypeクラスのプロパティを参照して型の分類を行う例です。 この例で使用しているデリゲート型の判定に関しては後述の[[#IsDelegate]]を参照してください。
+

          
+
#tabpage(codelang=cs,container-title=型の分類を行う例)
+
#code{{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    ClassifyType(typeof(int));
+
    ClassifyType(typeof(string));
+
    ClassifyType(typeof(double[]));
+
    ClassifyType(typeof(DateTime));
+
    ClassifyType(typeof(KeyValuePair<,>));
+
    ClassifyType(typeof(DayOfWeek));
+
    ClassifyType(typeof(List<>));
+
    ClassifyType(typeof(ICloneable));
+
    ClassifyType(typeof(IEnumerable<>));
+
    ClassifyType(typeof(EventHandler));
+
    ClassifyType(typeof(Action<>));
+
  }
+

          
+
  static void ClassifyType(Type t)
+
  {
+
    Console.Write("{0}: ", t.FullName);
+

          
+
    if (t.IsValueType) {
+
      if (t.IsEnum) {
+
        Console.WriteLine("列挙体");
+
      }
+
      else {
+
        if (t.IsPrimitive) {
+
          Console.WriteLine("値型(プリミティブ)");
+
        }
+
        else {
+
          if (t.IsGenericType)
+
            Console.Write("ジェネリック");
+

          
+
          Console.WriteLine("構造体");
+
        }
+
      }
+
    }
+
    else {
+
      if (t.IsArray) {
+
        Console.WriteLine("配列型");
+
      }
+
      else {
+
        if (t.IsGenericType)
+
          Console.Write("ジェネリック");
+

          
+
        if (t.IsInterface) {
+
          Console.WriteLine("インターフェイス型");
+
        }
+
        else {
+
          if (IsDelegate(t))
+
            Console.WriteLine("デリゲート型");
+
          else
+
            Console.WriteLine("クラス型");
+
        }
+
      }
+
    }
+
  }
+

          
+
  static bool IsDelegate(Type t)
+
  {
+
    return t.IsSubclassOf(typeof(Delegate)) || t.Equals(typeof(Delegate));
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ClassifyType(GetType(Integer))
+
    ClassifyType(GetType(String))
+
    ClassifyType(GetType(Double()))
+
    ClassifyType(GetType(DateTime))
+
    ClassifyType(GetType(KeyValuePair(Of ,)))
+
    ClassifyType(GetType(DayOfWeek))
+
    ClassifyType(GetType(List(Of)))
+
    ClassifyType(GetType(ICloneable))
+
    ClassifyType(GetType(IEnumerable(Of)))
+
    ClassifyType(GetType(EventHandler))
+
    ClassifyType(GetType(Action(Of)))
+
  End Sub
+

          
+
  Shared Sub ClassifyType(ByVal t As Type)
+
    Console.Write("{0}: ", t.FullName)
+

          
+
    If t.IsValueType Then
+
      If t.IsEnum Then
+
        Console.WriteLine("列挙体")
+
      Else
+
        If t.IsPrimitive Then
+
          Console.WriteLine("値型(プリミティブ)")
+
        Else
+
          If t.IsGenericType Then Console.Write("ジェネリック")
+

          
+
          Console.WriteLine("構造体")
+
        End If
+
      End If
+
    Else
+
      If t.IsArray Then
+
        Console.WriteLine("配列型")
+
      Else
+
        If t.IsGenericType Then Console.Write("ジェネリック")
+

          
+
        If t.IsInterface Then
+
          Console.WriteLine("インターフェイス型")
+
        Else
+
          If IsDelegate(t) Then
+
            Console.WriteLine("デリゲート型")
+
          Else
+
            Console.WriteLine("クラス型")
+
          End If
+
        End If
+
      End If
+
    End If
+
  End Sub
+

          
+
  Shared Function IsDelegate(ByVal t As Type) As Boolean
+
    Return t.IsSubclassOf(GetType([Delegate])) OrElse t.Equals(GetType([Delegate]))
+
  End Function
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
System.Int32: 値型(プリミティブ)
+
System.String: クラス型
+
System.Double[]: 配列型
+
System.DateTime: 構造体
+
System.Collections.Generic.KeyValuePair`2: ジェネリック構造体
+
System.DayOfWeek: 列挙体
+
System.Collections.Generic.List`1: ジェネリッククラス型
+
System.ICloneable: インターフェイス型
+
System.Collections.Generic.IEnumerable`1: ジェネリックインターフェイス型
+
System.EventHandler: デリゲート型
+
System.Action`1: ジェネリックデリゲート型
+
}}
+

          
+
型の種類・分類については[[programming/netfx/basic_types/0_characteristics]]や[[programming/netfx/valuetype_referencetype]]を合わせて参照してください。
+

          
+

          
+
****型がデリゲート型かどうか調べる [#IsDelegate]
+
Typeクラスには型がデリゲート型かどうかを調べる''``IsDelegate``のようなプロパティは用意されていません''。 Typeがデリゲート型を表すかどうかを調べたい場合は以下のような方法をとることができます。
+

          
+
#tabpage(codelang=cs,container-title=デリゲート型かどうかを調べる)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  static bool IsDelegate(Type t)
+
  {
+
    // 型がDelegate型またはDelegate型の派生クラスの場合はデリゲート型と判定する
+
    return t.IsSubclassOf(typeof(Delegate)) || t.Equals(typeof(Delegate));
+
  }
+

          
+
  public static void Main()
+
  {
+
    foreach (var t in new[] {
+
      typeof(EventHandler),
+
      typeof(Action<,>),
+
      typeof(Delegate),
+
      typeof(MulticastDelegate),
+
      typeof(ICloneable),
+
    }) {
+
      Console.WriteLine("IsDelegate({0}) = {1}", t, IsDelegate(t));
+
    }
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Shared Function IsDelegate(ByVal t As Type) As Boolean
+
    ' 型がDelegate型またはDelegate型の派生クラスの場合はデリゲート型と判定する
+
    Return t.IsSubclassOf(GetType([Delegate])) OrElse t.Equals(GetType([Delegate]))
+
  End Function
+

          
+
  Public Shared Sub Main()
+
    For Each t As Type In New Type() { _
+
      GetType(EventHandler), _
+
      GetType(Action(Of ,)), _
+
      GetType([Delegate]), _
+
      GetType([MulticastDelegate]), _
+
      GetType(ICloneable) _
+
    }
+
      Console.WriteLine("IsDelegate({0}) = {1}", t, IsDelegate(t))
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
IsDelegate(System.EventHandler) = True
+
IsDelegate(System.Action`2[T1,T2]) = True
+
IsDelegate(System.Delegate) = True
+
IsDelegate(System.MulticastDelegate) = True
+
IsDelegate(System.ICloneable) = False
+
}}
+

          
+
-関連
+
--[[programming/netfx/tips/check_type_isassignablefrom_issubclassof]]
+
--[[programming/netfx/tips/get_delegate_signature_from_type]]
+
--[[programming/netfx/delegate/2_operations]]
+

          
+

          
+
****実装しているインターフェイスを調べる
+
型が実装するすべてのインターフェイスを取得するには&msdn(netfx,member,System.Type.GetInterfaces){GetInterfacesメソッド};を使うことができます。 一方、型が特定のインターフェイスを実装しているかどうかについては、&msdn(netfx,member,System.Type.GetInterface){GetInterfaceメソッド};でインターフェイス名を文字列で指定して調べるか、&msdn(netfx,member,System.Type.IsAssignableFrom){IsAssignableFromメソッド};を使ってインターフェイス型への代入を行えるかどうかを調べることによって知ることができます。
+

          
+
#tabpage(codelang=cs,container-title=実装しているインターフェイスを調べる)
+
#code{{
+
using System;
+
using System.Collections.Generic;
+
using System.Reflection;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    var t = typeof(List<int>);
+

          
+
    // List<int>クラスが実装するインターフェイスをすべて取得して表示する
+
    foreach (var ti in t.GetInterfaces()) {
+
      Console.WriteLine(ti);
+
    }
+
    Console.WriteLine();
+

          
+
    // IEnumerable<T>インターフェイスを実装しているか調べる
+
    Console.WriteLine(t.GetInterface("System.Collections.Generic.IEnumerable`1") != null);
+

          
+
    // 型がIEnumerable<int>インターフェイスに代入可能かを調べる
+
    Console.WriteLine(typeof(IEnumerable<int>).IsAssignableFrom(t));
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Collections.Generic
+
Imports System.Reflection
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t As Type = GetType(List(Of Integer))
+

          
+
    ' List(Of Integer)クラスが実装するインターフェイスをすべて取得して表示する
+
    For Each ti As Type In t.GetInterfaces()
+
      Console.WriteLine(ti)
+
    Next
+
    Console.WriteLine()
+

          
+
    ' IEnumerable(Of T)インターフェイスを実装しているか調べる
+
    Console.WriteLine(t.GetInterface("System.Collections.Generic.IEnumerable`1") IsNot Nothing)
+

          
+
    ' 型がIEnumerable(Of Integer)インターフェイスに代入可能かを調べる
+
    Console.WriteLine(GetType(IEnumerable(Of Integer)).IsAssignableFrom(t))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
System.Collections.Generic.IList`1[System.Int32]
+
System.Collections.Generic.IReadOnlyList`1[System.Int32]
+
System.Collections.ICollection
+
System.Collections.Generic.ICollection`1[System.Int32]
+
System.Collections.IEnumerable
+
System.Collections.Generic.IEnumerable`1[System.Int32]
+
System.Collections.Generic.IReadOnlyCollection`1[System.Int32]
+
System.Collections.IList
+

          
+
True
+
True
+
}}
+

          
+
これに関して、型情報からインターフェイスの代入可能性を判定する方法については[[programming/netfx/tips/check_type_isassignablefrom_issubclassof]]で解説しています。
+

          
+

          
+
****型パラメータ情報の取得 [#Type.GetGenericArguments]
+
ジェネリック型の型パラメータを取得したい場合は&msdn(netfx,member,System.Type.GetGenericArguments){GetGenericArgumentsメソッド};を使うことができます。 型パラメータの情報もTypeクラスとして取得されます。 Typeが型パラメータを表す場合、&msdn(netfx,member,System.Type.IsGenericParameter){IsGenericParameterプロパティ};がtrueとなります。
+

          
+
#tabpage(codelang=cs,container-title=ジェネリック型と型パラメータの型情報)
+
#code{{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    ClassifyGenericType(typeof(List<>));
+
    ClassifyGenericType(typeof(List<int>));
+
    ClassifyGenericType(typeof(List<string>));
+
    ClassifyGenericType(typeof(Dictionary<,>));
+
    ClassifyGenericType(typeof(Dictionary<string, int>));
+
    ClassifyGenericType(typeof(Action<,,,>));
+
    ClassifyGenericType(typeof(Action<int, float, double, string>));
+
    ClassifyGenericType(typeof(int));
+
  }
+

          
+
  static void ClassifyGenericType(Type t)
+
  {
+
    Console.Write("{0}: ", t.Name);
+

          
+
    if (t.IsGenericType) {
+
      if (t.IsGenericTypeDefinition)
+
        Console.Write("ジェネリック型定義; ");
+
      else
+
        Console.Write("構築ジェネリック型; ");
+

          
+
      foreach (var ta in t.GetGenericArguments()) {
+
        Console.Write("{0}, ", ta.Name);
+
      }
+
      Console.WriteLine();
+
    }
+
    else {
+
      Console.WriteLine("(非ジェネリック型)");
+
    }
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ClassifyGenericType(GetType(List(Of)))
+
    ClassifyGenericType(GetType(List(Of Integer)))
+
    ClassifyGenericType(GetType(List(Of String)))
+
    ClassifyGenericType(GetType(Dictionary(Of ,)))
+
    ClassifyGenericType(GetType(Dictionary(Of String, Integer)))
+
    ClassifyGenericType(GetType(Action(Of ,,,)))
+
    ClassifyGenericType(GetType(Action(Of Integer, Single, Double, String)))
+
    ClassifyGenericType(GetType(Integer))
+
  End Sub
+

          
+
  Shared Sub ClassifyGenericType(ByVal t As Type)
+
    Console.Write("{0}: ", t.Name)
+

          
+
    If t.IsGenericType Then
+
      If t.IsGenericTypeDefinition Then
+
        Console.Write("ジェネリック型定義; ")
+
      Else
+
        Console.Write("構築ジェネリック型; ")
+
      End If
+

          
+
      For Each ta As Type In t.GetGenericArguments()
+
        Console.Write("{0}, ", ta.Name)
+
      Next
+
      Console.WriteLine()
+
    Else
+
      Console.WriteLine("(非ジェネリック型)")
+
    End If
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
List`1: ジェネリック型定義; T, 
+
List`1: 構築ジェネリック型; Int32, 
+
List`1: 構築ジェネリック型; String, 
+
Dictionary`2: ジェネリック型定義; TKey, TValue, 
+
Dictionary`2: 構築ジェネリック型; String, Int32, 
+
Action`4: ジェネリック型定義; T1, T2, T3, T4, 
+
Action`4: 構築ジェネリック型; Int32, Single, Double, String, 
+
Int32: (非ジェネリック型)
+
}}
+

          
+
ジェネリックメソッドの型パラメータも同様に取得することができます。 この場合、まず対象となるジェネリックメソッドの[[MethodInfo>#Type.GetMembers]]を取得し、その後&msdn(netfx,member,System.Reflection.MethodInfo.GetGenericArguments){MethodInfo.GetGenericArguments};メソッドを呼び出します。
+

          
+
#tabpage(codelang=cs,container-title=ジェネリックメソッドの型パラメータを取得する例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  public void M<TArg1, TArg2>(TArg1 arg1, TArg2 arg2)
+
  {
+
  }
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    // メソッドC.M<T>のメソッド情報を取得する
+
    MethodInfo m = typeof(C).GetMethod("M");
+

          
+
    Console.Write("{0}: ", m.Name);
+

          
+
    foreach (var ta in m.GetGenericArguments()) {
+
      Console.Write("{0}, ", ta.Name);
+
    }
+
    Console.WriteLine();
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C
+
  Public Sub M(Of TArg1, TArg2)(ByVal arg1 As TArg1, ByVal arg2 As TArg2)
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ' メソッドC.M<T>のメソッド情報を取得する
+
    Dim m As MethodInfo = GetType(C).GetMethod("M")
+

          
+
    Console.Write("{0}: ", m.Name)
+

          
+
    For Each ta As Type In m.GetGenericArguments()
+
      Console.Write("{0}, ", ta.Name)
+
    Next
+
    Console.WriteLine()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
M: TArg1, TArg2,
+
}}
+

          
+
この例で使用している&msdn(netfx,member,System.Type.GetMethod){GetMethodメソッド};については後述の[[#Type.GetMembers]]で解説しています。
+

          
+
ジェネリック型の型パラメータを表すTypeでは&msdn(netfx,member,System.Type.DeclaringType){DeclaringTypeプロパティ};、ジェネリックメソッドの型パラメータを表すTypeでは&msdn(netfx,member,System.Type.DeclaringType){DeclaringMethodプロパティ};を参照すると、型パラメータの宣言されている型(またはメソッド)を参照することができます。
+

          
+
#tabpage(codelang=cs,container-title=型パラメータが宣言されている型・メソッドを取得する例)
+
#code{{
+
using System;
+
using System.Collections.Generic;
+
using System.Reflection;
+

          
+
class C {
+
  public void M<TArg1, TArg2>(TArg1 arg1, TArg2 arg2)
+
  {
+
  }
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    // ジェネリック型List<T>の型パラメータTの型情報を取得する
+
    Type arg1 = typeof(List<>).GetGenericArguments()[0];
+

          
+
    // 型パラメータが宣言されている型を表示する
+
    Console.WriteLine("{0} -> {1}", arg1, arg1.DeclaringType);
+

          
+
    // ジェネリックメソッドC.M<T>の型パラメータTの型情報を取得する
+
    Type arg2 = typeof(C).GetMethod("M").GetGenericArguments()[0];
+

          
+
    // 型パラメータが宣言されているメソッドを表示する
+
    Console.WriteLine("{0} -> {1}", arg2, arg2.DeclaringMethod);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Collections.Generic
+
Imports System.Reflection
+

          
+
Class C
+
  Public Sub M(Of TArg1, TArg2)(ByVal arg1 As TArg1, ByVal arg2 As TArg2)
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ' ジェネリック型List(Of T)の型パラメータTの型情報を取得する
+
    Dim arg1 As Type = GetType(List(Of)).GetGenericArguments()(0)
+

          
+
    ' 型パラメータが宣言されている型を表示する
+
    Console.WriteLine("{0} -> {1}", arg1, arg1.DeclaringType)
+

          
+
    ' ジェネリックメソッドC.M<T>の型パラメータTの型情報を取得する
+
    Dim arg2 As Type = GetType(C).GetMethod("M").GetGenericArguments()(0)
+

          
+
    ' 型パラメータが宣言されているメソッドを表示する
+
    Console.WriteLine("{0} -> {1}", arg2, arg2.DeclaringMethod)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
T -> System.Collections.Generic.List`1[T]
+
TArg1 -> Void M[TArg1,TArg2](TArg1, TArg2)
+
}}
+

          
+

          
+
***メンバ情報の取得 (MemberInfo) [#Type.GetMembers]
+
Typeクラスでは次のようなメソッドによって型で定義されているメンバの情報を取得することができます。
+

          
+
|*Typeクラスのメソッド
+
|~メソッド|~動作|h
+
|&msdn(netfx,member,System.Type.GetMember){GetMember};&br;&msdn(netfx,member,System.Type.GetMembers){GetMembers};|指定された名前のメンバ、あるいはすべてのメンバを取得する。 メンバ情報は&msdn(netfx,type,System.Reflection.MemberInfo){MemberInfoクラス};で返される。|
+
|&msdn(netfx,member,System.Type.GetConstructor){GetConstructor};&br;&msdn(netfx,member,System.Type.GetConstructors){GetConstructors};|指定された引数リストのコンストラクタ、あるいはすべてのメンバを取得する。 &msdn(netfx,type,System.Reflection.ConstructorInfo){ConstructorInfoクラス};が返される。|
+
|&msdn(netfx,member,System.Type.GetEvent){GetEvent};&br;&msdn(netfx,member,System.Type.GetEvents){GetEvents};|指定された名前のイベント、あるいはすべてのイベントを取得する。 &msdn(netfx,type,System.Reflection.EventInfo){EventInfoクラス};が返される。|
+
|&msdn(netfx,member,System.Type.GetField){GetField};&br;&msdn(netfx,member,System.Type.GetFields){GetFields};|指定された名前のフィールド、あるいはすべてのフィールドを取得する。 &msdn(netfx,type,System.Reflection.FieldInfo){FieldInfoクラス};が返される。|
+
|&msdn(netfx,member,System.Type.GetMethod){GetMethod};&br;&msdn(netfx,member,System.Type.GetMethods){GetMethods};|指定された名前・引数リストのメソッド、あるいはすべてのメソッドを取得する。 &msdn(netfx,type,System.Reflection.MethodInfo){MethodInfoクラス};が返される。|
+
|&msdn(netfx,member,System.Type.GetProperty){GetProperty};&br;&msdn(netfx,member,System.Type.GetProperties){GetProperties};|指定された名前のプロパティ、あるいはすべてのプロパティを取得する。 &msdn(netfx,type,System.Reflection.PropertyInfo){PropertyInfoクラス};が返される。|
+

          
+
戻り値として返されるMethodInfoなどのクラスはすべてMemberInfoクラスから派生したクラスとなっています。 &msdn(netfx,member,System.Reflection.MemberInfo.MemberType){MemberTypeプロパティ};を参照するとメンバの種類を&msdn(netfx,type,System.Reflection.MemberTypes){MemberTypes列挙体};で取得することができます。
+

          
+
#tabpage(codelang=cs,container-title=クラスからすべてのメンバを取得する例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  public void M() {} // メソッド
+
  public int P { get; set; } // プロパティ
+
  public string F = null; // フィールド
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    var t = typeof(C);
+

          
+
    // クラスCのすべてのメンバを取得して表示する
+
    foreach (MemberInfo m in t.GetMembers()) {
+
      Console.WriteLine("{0}\t{1}", m.MemberType, m);
+
    }
+
    Console.WriteLine();
+

          
+
    // 名前がFのフィールドを取得する
+
    FieldInfo f = t.GetField("F");
+

          
+
    Console.WriteLine(f);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C
+
  Public Sub M() ' メソッド
+
  End Sub
+

          
+
  Public Property P As Integer ' プロパティ
+
  Public F As String = Nothing ' フィールド
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t As Type = GetType(C)
+

          
+
    ' クラスCのすべてのメンバを取得して表示する
+
    For Each m As MemberInfo In t.GetMembers()
+
      Console.WriteLine("{0}{1}{2}", m.MemberType, vbTab, m)
+
    Next
+
    Console.WriteLine()
+

          
+
    ' 名前がFのフィールドを取得する
+
    Dim f As FieldInfo = t.GetField("F")
+

          
+
    Console.WriteLine(f)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Method	Int32 get_P()
+
Method	Void set_P(Int32)
+
Method	Void M()
+
Method	Boolean Equals(System.Object)
+
Method	Int32 GetHashCode()
+
Method	System.Type GetType()
+
Method	System.String ToString()
+
Constructor	Void .ctor()
+
Property	Int32 P
+
Field	System.String F
+

          
+
System.String F
+
}}
+

          
+
このようにして取得したMemberInfoを使うことにより、[[メソッドの呼び出しやフィールドの取得・設定などの操作>#MemberInfo_Invoke]]を行うことができます。
+

          
+
****メンバ情報の取得とBindingFlags [#GetMembers_BindingFlags]
+
GetMembersなどメンバ情報を取得するメソッドでは、特に引数を指定しない場合はパブリックなインスタンスメンバのみを返します。 非パブリックやクラスのメンバ(静的メンバ)を取得したい場合は&msdn(netfx,type,System.Reflection.BindingFlags){BindingFlags};を指定する必要があります。 BindingFlagsには次のような値が用意されています。
+

          
+
|*メンバ情報の取得とBindingFlags
+
|~値|~意味|~備考|h
+
|&msdn(netfx,member,System.Reflection.BindingFlags.Static){BindingFlags.Static};|静的メンバを対象とする|どちらか一方または両方を指定する必要があります|
+
|&msdn(netfx,member,System.Reflection.BindingFlags.Instance){BindingFlags.Instance};|インスタンスメンバを対象とする|~|
+
|&msdn(netfx,member,System.Reflection.BindingFlags.Public){BindingFlags.Public};|パブリックメンバを対象とする|どちらか一方または両方を指定する必要があります|
+
|&msdn(netfx,member,System.Reflection.BindingFlags.NonPublic){BindingFlags.NonPublic};|非パブリックメンバを対象とする|~|
+
|&msdn(netfx,member,System.Reflection.BindingFlags.IgnoreCase){BindingFlags.IgnoreCase};|メンバの名前を指定する際に、大文字小文字の違いを無視する||
+
|&msdn(netfx,member,System.Reflection.BindingFlags.DeclaredOnly){BindingFlags.DeclaredOnly};|その型で宣言されているメンバのみを対象とする (継承されたメンバを含めない)||
+
|&msdn(netfx,member,System.Reflection.BindingFlags.FlattenHierarchy){BindingFlags.FlattenHierarchy};|継承された静的メンバを対象とする||
+
|~値|~意味|~備考|f
+

          
+
#tabpage(codelang=cs,container-title=クラスの非パブリックなメンバのみを取得して表示する例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  public void M1() {}
+
  protected void M2() {}
+
  private void M3() {}
+
  private static void M4() {}
+

          
+
  public string F1 = null;
+
  private string F2 = null;
+
  private static string F3 = null;
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    var t = typeof(C);
+

          
+
    // 非パブリックなインスタンスメンバのみを取得して列挙する
+
    foreach (MemberInfo m in t.GetMembers(BindingFlags.NonPublic | BindingFlags.Instance)) {
+
      Console.WriteLine("{0}\t{1}", m.MemberType, m);
+
    }
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C
+
  Public Sub M1()
+
  End Sub
+

          
+
  Protected Sub M2()
+
  End Sub
+

          
+
  Private Sub M3()
+
  End Sub
+

          
+
  Private Shared Sub M4()
+
  End Sub
+

          
+
  Public F1 As String = Nothing
+
  Private F2 As String = Nothing
+
  Private Shared F3 As String = Nothing
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t As Type = GetType(C)
+

          
+
    ' 非パブリックなインスタンスメンバのみを取得して列挙する
+
    For Each m As MemberInfo In t.GetMembers(BindingFlags.NonPublic Or BindingFlags.Instance)
+
      Console.WriteLine("{0}{1}{2}", m.MemberType, vbTab, m)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Method	Void M2()
+
Method	Void M3()
+
Method	Void Finalize()
+
Method	System.Object MemberwiseClone()
+
Field	System.String F2
+
}}
+

          
+
#tabpage(codelang=cs,container-title=対象のクラスで宣言されているメンバのみを取得する例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C1 {
+
  public void M1() {}
+
}
+

          
+
class C2 : C1 {
+
  public void M2() {}
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    var t = typeof(C2);
+

          
+
    // C2クラスで宣言されているメンバのみを取得して列挙する
+
    foreach (MemberInfo m in t.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)) {
+
      Console.WriteLine("{0}\t{1}", m.MemberType, m);
+
    }
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C1
+
  Public Sub M1()
+
  End Sub
+
End Class
+

          
+
Class C2
+
  Inherits C1
+

          
+
  Public Sub M2()
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t As Type = GetType(C2)
+

          
+
    ' C2クラスで宣言されているメンバのみを取得して列挙する
+
    For Each m As MemberInfo In t.GetMembers(BindingFlags.DeclaredOnly Or BindingFlags.Public Or BindingFlags.Instance)
+
      Console.WriteLine("{0}{1}{2}", m.MemberType, vbTab, m)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Method	Void M2()
+
Constructor	Void .ctor()
+
}}
+

          
+
****プロパティのアクセサメソッドの取得
+
PropertyInfoからはプロパティの``get``アクセサ/``set``アクセサに対応するMethodInfoをそれぞれ個別に取得することができます。 それぞれ&msdn(netfx,member,System.Reflection.PropertyInfo.GetMethod){GetMethodプロパティ};/&msdn(netfx,member,System.Reflection.PropertyInfo.SetMethod){SetMethodプロパティ};プロパティを参照することでMethodInfoとして取得できます。 読み取り専用/書き込み専用プロパティの場合は``null``/``Nothing``が返されます。
+

          
+
#tabpage(codelang=cs,container-title=プロパティのアクセサメソッドを取得する例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  public int P {get; set;}
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    var t = typeof(C);
+

          
+
    PropertyInfo p = t.GetProperty("P"); // プロパティPのPropertyInfoを取得
+

          
+
    MethodInfo getter = p.GetMethod; // プロパティPのgetアクセサメソッドを取得
+
    MethodInfo setter = p.SetMethod; // プロパティPのsetアクセサメソッドを取得
+

          
+
    Console.WriteLine(getter);
+
    Console.WriteLine(setter);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C
+
  Public Property P As Integer
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t As Type = GetType(C)
+

          
+
    Dim p As PropertyInfo = t.GetProperty("P") ' プロパティPのPropertyInfoを取得
+

          
+
    Dim getter As MethodInfo = p.GetMethod ' プロパティPのGetアクセサメソッドを取得
+
    Dim setter As MethodInfo = p.SetMethod ' プロパティPのSetアクセサメソッドを取得
+

          
+
    Console.WriteLine(getter)
+
    Console.WriteLine(setter)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Int32 get_P()
+
Void set_P(Int32)
+
}}
+

          
+

          
+
****引数リストを指定した取得
+
コンストラクタは名前を持たないため名前で区別することができず、またメソッドではオーバーロードによって同じ名前のメソッドが複数存在する場合があります。 このようにメンバ名では特定のメンバを限定できない場合には、引数リストを指定することによって取得対象を限定することができます。 引数リストは次の例のようにTypeの配列で指定します。 引数がない場合は空の配列か、&msdn(netfx,member,System.Type.EmptyTypes){Type.EmptyTypesフィールド};を指定します。 ''引数の型・数・順序のすべてに一致''するものがなければ``null``/``Nothing``が返されます。
+

          
+
#tabpage(codelang=cs,container-title=引数リストを指定してコンストラクタを取得する例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  public C(int x) {}
+
  public C(string x, int y) {}
+
  public C() {}
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    var t = typeof(C);
+

          
+
    // int型の引数を一つとるコンストラクタを取得する
+
    ConstructorInfo ctor1 = t.GetConstructor(new[] {typeof(int)});
+

          
+
    // string型とint型の引数をとるコンストラクタを取得する
+
    ConstructorInfo ctor2 = t.GetConstructor(new[] {typeof(string), typeof(int)});
+

          
+
    // 引数のないコンストラクタを取得する
+
    ConstructorInfo ctor3 = t.GetConstructor(Type.EmptyTypes);
+

          
+
    Console.WriteLine(ctor1);
+
    Console.WriteLine(ctor2);
+
    Console.WriteLine(ctor3);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C
+
  Public Sub New(ByVal x As Integer)
+
  End Sub
+

          
+
  Public Sub New(ByVal x As String, ByVal y As Integer)
+
  End Sub
+

          
+
  Public Sub New()
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t As Type = GetType(C)
+

          
+
    ' Integer型の引数を一つとるコンストラクタを取得する
+
    Dim ctor1 As ConstructorInfo = t.GetConstructor(New Type() {GetType(Integer)})
+

          
+
    ' String型とInteger型の引数をとるコンストラクタを取得する
+
    Dim ctor2 As ConstructorInfo = t.GetConstructor(New Type() {GetType(String), GetType(Integer)})
+

          
+
    ' 引数のないコンストラクタを取得する
+
    Dim ctor3 As ConstructorInfo = t.GetConstructor(Type.EmptyTypes)
+

          
+
    Console.WriteLine(ctor1)
+
    Console.WriteLine(ctor2)
+
    Console.WriteLine(ctor3)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Void .ctor(Int32)
+
Void .ctor(String, Int32)
+
Void .ctor()
+
}}
+

          
+
#tabpage(codelang=cs,container-title=引数リストを指定してメソッドのオーバーロードを限定して取得する例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  public void M(int x) {}
+
  public void M(int x, int y) {}
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    var t = typeof(C);
+

          
+
    // int型の引数を1つとるメソッドMのオーバーロードを取得する
+
    MethodInfo m1 = t.GetMethod("M", new[] {typeof(int)});
+

          
+
    // int型の引数を2つとるメソッドMのオーバーロードを取得する
+
    MethodInfo m2 = t.GetMethod("M", new[] {typeof(int), typeof(int)});
+

          
+
    Console.WriteLine(m1);
+
    Console.WriteLine(m2);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C
+
  Public Overloads Sub M(ByVal x As Integer)
+
  End Sub
+

          
+
  Public Overloads Sub M(ByVal x As Integer, ByVal y As Integer)
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t As Type = GetType(C)
+

          
+
    ' Integer型の引数を1つとるメソッドMのオーバーロードを取得する
+
    Dim m1 As MethodInfo = t.GetMethod("M", New Type() {GetType(Integer)})
+

          
+
    ' Integer型の引数を2つとるメソッドMのオーバーロードを取得する
+
    Dim m2 As MethodInfo = t.GetMethod("M", New Type() {GetType(Integer), GetType(Integer)})
+

          
+
    Console.WriteLine(m1)
+
    Console.WriteLine(m2)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Void M(Int32)
+
Void M(Int32, Int32)
+
}}
+

          
+

          
+

          
+

          
+
*インスタンスの操作
+
.NET Frameworkではリフレクションによって型情報を取得するだけでなく、取得した型情報を使ってインスタンスを作成したり、フィールドの書き換えやメソッドの呼び出しなどインスタンスに対する操作を行うこともできるようになっています。
+

          
+
**インスタンスの作成 (Activator.CreateInstance) [#Activator.CreateInstance]
+
&msdn(netfx,member,System.Activator.CreateInstance){Activator.CreateInstanceメソッド};を使用すると、型情報を使って動的にインスタンスを作成することができます。 このメソッドではインスタンスを生成する際、コンストラクタに渡す引数を指定することができます。 コンストラクタに渡す引数は``object``型の配列で指定します。 指定された引数に応じて適切なコンストラクタが自動的に呼び出されます。 当然、抽象クラスのインスタンスを作成しようとしたり、引数と一致するコンストラクタがない場合は例外がスローされます。
+

          
+
#tabpage(codelang=cs,container-title=Activator.CreateInstanceを使ったインスタンスの作成)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  private int f;
+

          
+
  public C()
+
  {
+
    this.f = 0;
+
  }
+

          
+
  public C(int f)
+
  {
+
    this.f = f;
+
  }
+

          
+
  public override string ToString()
+
  {
+
    return string.Format("f = {0}", f);
+
  }
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    object inst;
+

          
+
    // デフォルト(引数なし)のコンストラクタを使ってインスタンスを作成する
+
    inst = Activator.CreateInstance(typeof(C));
+

          
+
    Console.WriteLine(inst);
+

          
+
    // int型の引数を1つとるコンストラクタを使ってインスタンスを作成する
+
    object[] args = new object[] {42};
+

          
+
    inst = Activator.CreateInstance(typeof(C), BindingFlags.CreateInstance, null, args, null);
+

          
+
    Console.WriteLine(inst);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C
+
  Private f As Integer
+

          
+
  Public Sub New()
+
    Me.f = 0
+
  End Sub
+

          
+
  Public Sub New(ByVal f As Integer)
+
    Me.f = f
+
  End Sub
+

          
+
  Public Overrides Function ToString() As String
+
    Return String.Format("f = {0}", f)
+
  End Function
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim inst As Object
+

          
+
    ' デフォルト(引数なし)のコンストラクタを使ってインスタンスを作成する
+
    inst = Activator.CreateInstance(GetType(C))
+

          
+
    Console.WriteLine(inst)
+

          
+
    ' Integer型の引数を1つとるコンストラクタを使ってインスタンスを作成する
+
    Dim args As Object() = New Object() {42}
+

          
+
    inst = Activator.CreateInstance(GetType(C), BindingFlags.CreateInstance, Nothing, args, Nothing)
+

          
+
    Console.WriteLine(inst)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
f = 0
+
f = 42
+
}}
+

          
+
作成したインスタンスは``object``で返されるため、インスタンスを使用するには既知の型の場合はその型にキャストするか、それ以外の場合は[[後述する方法>#invoke_member]]でリフレクションによって操作を行います。
+

          
+
#tabpage(codelang=cs,container-title=Activator.CreateInstanceで作成したインスタンスを操作する例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  public void M()
+
  {
+
    Console.WriteLine("Hello, world!");
+
  }
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    Type t = typeof(C);
+

          
+
    object inst = Activator.CreateInstance(t);
+

          
+
    // InvokeMemberメソッドを使って作成したインスタンスのメソッドMを呼び出す
+
    t.InvokeMember("M", BindingFlags.InvokeMethod, null, inst, null);
+

          
+
    // インスタンスをキャストして直接メソッドMを呼び出す
+
    C c = (C)inst;
+

          
+
    c.M();
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C
+
  Public Sub M()
+
    Console.WriteLine("Hello, world!")
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t As Type = GetType(C)
+

          
+
    Dim inst As Object = Activator.CreateInstance(t)
+

          
+
    ' 作成したインスタンスのメソッドMを呼び出す
+
    t.InvokeMember("M", BindingFlags.InvokeMethod, Nothing, inst, Nothing)
+

          
+
    ' インスタンスをキャストして直接メソッドMを呼び出す
+
    Dim c As C = DirectCast(inst, C)
+

          
+
    c.M()
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Hello, world!
+
Hello, world!
+
}}
+

          
+
Activator.CreateInstanceメソッドのほか、後述する[[Type.InvokeMemberメソッド>#Type.InvokeMember]]や[[ConstructorInfo.Invokeメソッド>#ConstructorInfo.Invoke]]でも型情報からインスタンスを作成することができます。
+

          
+
このように型情報が取得できれば動的にインスタンスを作成して操作することができます。 また、動的にアセンブリを読み込み、読み込んだアセンブリに含まれるインスタンスを作成するといったことも可能です。
+

          
+
***Activator.CreateInstanceとパフォーマンス
+
Activator.CreateInstanceによるインスタンスの作成は、コンストラクタを直接呼び出す場合と比較するとオーバーヘッドが大きいため、パフォーマンスに影響します。 インスタンス作成にかかる時間を計測して比較すると次のようになります。 コンストラクタを使ったインスタンスが行える場合は、そちらを優先すべきです。
+

          
+
#prompt(Windows 7 + .NET Framework 4.5での比較結果){{
+
               new(): 00:00:00.0213256
+
      CreateInstance: 00:00:00.1682794
+
               new(): 00:00:00.0206288
+
      CreateInstance: 00:00:00.1625131
+
               new(): 00:00:00.0195052
+
      CreateInstance: 00:00:00.1609271
+
               new(): 00:00:00.0203098
+
      CreateInstance: 00:00:00.1609503
+
               new(): 00:00:00.0205671
+
      CreateInstance: 00:00:00.1606695
+
}}
+

          
+
#prompt(Ubuntu 14.04 + Mono 3.10での比較結果){{
+
               new(): 00:00:00.0152867
+
      CreateInstance: 00:00:00.4069424
+
               new(): 00:00:00.0102610
+
      CreateInstance: 00:00:00.4079876
+
               new(): 00:00:00.0118173
+
      CreateInstance: 00:00:00.4059866
+
               new(): 00:00:00.0105222
+
      CreateInstance: 00:00:00.4039274
+
               new(): 00:00:00.0103997
+
      CreateInstance: 00:00:00.4043431
+
}}
+

          
+
#code(cs,計測に用いたコード){{
+
using System;
+
using System.Diagnostics;
+

          
+
public class C {
+
  public C() {}
+
}
+

          
+
public class Test {
+
  public static void Main()
+
  {
+
    for (var act = 0; act < 5; act++) {
+
      var sw1 = Stopwatch.StartNew();
+

          
+
      for (var i = 0; i < 1000 * 1000; i++) {
+
        new C();
+
      }
+

          
+
      sw1.Stop();
+

          
+
      Console.WriteLine("{0, 20}: {1}", "new()", sw1.Elapsed);
+

          
+
      var t = typeof(C);
+
      var sw2 = Stopwatch.StartNew();
+

          
+
      for (var i = 0; i < 1000 * 1000; i++) {
+
        Activator.CreateInstance(t);
+
      }
+

          
+
      sw2.Stop();
+

          
+
      Console.WriteLine("{0, 20}: {1}", "CreateInstance", sw2.Elapsed);
+
    }
+
  }
+
}
+
}}
+

          
+
インスタンスの生成に限らず、一般にリフレクションによる操作には大きなオーバーヘッドが伴います。
+

          
+

          
+
**メンバの呼び出し [#invoke_member]
+
***Type.InvokeMember [#Type.InvokeMember]
+
&msdn(netfx,member,System.Type.InvokeMember){Type.InvokeMemberメソッド};を使うと型情報とメンバ名を使ってメンバの呼び出しを行うことができます。 InvokeMemberメソッドでは、メソッドの呼び出しのほか、プロパティの値の取得・設定、フィールドの値の取得・設定を行うことができます。 またコンストラクタを呼び出すことによってインスタンスを作成することもできます。 呼び出すメンバに応じて、次のBindingFlagsのいずれかを指定します。
+

          
+
|*InvokeMemberメソッドとBindingFlags
+
|~BindingFlags|~InvomeMemberメソッドの動作|h
+
|&msdn(netfx,member,System.Reflection.BindingFlags.InvokeMethod){BindingFlags.InvokeMethod};|指定した名前・引数と一致するメソッドを呼び出して戻り値を取得する|
+
|&msdn(netfx,member,System.Reflection.BindingFlags.SetProperty){BindingFlags.SetProperty};|指定した名前のプロパティに値を設定する|
+
|&msdn(netfx,member,System.Reflection.BindingFlags.GetProperty){BindingFlags.GetProperty};|指定した名前のプロパティの値を取得する|
+
|&msdn(netfx,member,System.Reflection.BindingFlags.SetField){BindingFlags.SetField};|指定した名前のフィールドに値を設定する|
+
|&msdn(netfx,member,System.Reflection.BindingFlags.GetField){BindingFlags.GetField};|指定した名前のフィールドの値を取得する|
+
|&msdn(netfx,member,System.Reflection.BindingFlags.CreateInstance){BindingFlags.CreateInstance};|指定した引数と一致するコンストラクタを呼び出してインスタンスを作成する|
+

          
+
これらの値に加えて、非パブリックメンバを呼び出したり、メンバ名の大文字小文字の違いを無視して呼び出せるようにするために[[BindingFlags.NonPublicやBindingFlags.IgnoreCase>#GetMembers_BindingFlags]]などを組み合わせて指定することもできます。
+

          
+
InvokeMemberメソッドでは、第4引数に操作の対象となるインスタンスを指定します。 静的メンバの場合はインスタンスを指定する代わりに``null``/``Nothing``を指定します。 メソッドおよびコンストラクタの呼び出し時に渡す引数や、フィールド・プロパティに設定する値は、``object``型の配列に格納して第5引数に指定します。 引数がない場合は``null``/``Nothing``を指定します。
+

          
+
また、``BindingFlags.InvokeMethod``で呼び出したメソッドの戻り値や、``BindingFlags.CreateInstance``で作成したインスタンス、``BindingFlags.GetProperty``および``BindingFlags.GetField``で取得したプロパティ・フィールドの値はInvokeMemberメソッドの戻り値として取得することができます。
+

          
+
#tabpage(codelang=cs,container-title=Type.InvokeMemberを使ってメンバの呼び出しを行う例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  public string M(string s)
+
  {
+
    return s.ToUpper();
+
  }
+

          
+
  public int P { get; set; }
+

          
+
  public double F = 0.0;
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    Type t = typeof(C);
+

          
+
    object inst = Activator.CreateInstance(t);
+

          
+
    // インスタンスのメソッドMを呼び出す
+
    object ret = t.InvokeMember("M", BindingFlags.InvokeMethod, null, inst, new object[] {"Hello, world!"});
+

          
+
    Console.WriteLine(ret); // メソッドの戻り値を表示する
+

          
+
    // プロパティPに値42を設定する
+
    t.InvokeMember("P", BindingFlags.SetProperty, null, inst, new object[] {42});
+

          
+
    // プロパティPの値を取得する
+
    object p = t.InvokeMember("P", BindingFlags.GetProperty, null, inst, null);
+

          
+
    Console.WriteLine("P = {0}", p);
+

          
+
    // フィールドFに値3.14を設定する
+
    t.InvokeMember("F", BindingFlags.SetField, null, inst, new object[] {3.14});
+

          
+
    // フィールドFの値を取得する
+
    object f = t.InvokeMember("F", BindingFlags.GetField, null, inst, null);
+

          
+
    Console.WriteLine("F = {0}", f);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C
+
  Public Function M(ByVal s As String) As String
+
    Return s.ToUpper()
+
  End Function
+

          
+
  Public Property P As Integer
+

          
+
  Public F As Double = 0.0
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t As Type = GetType(C)
+

          
+
    Dim inst As Object = Activator.CreateInstance(t)
+

          
+
    ' インスタンスのメソッドMを呼び出す
+
    Dim ret As Object = t.InvokeMember("M", BindingFlags.InvokeMethod, Nothing, inst, New Object() {"Hello, world!"})
+

          
+
    Console.WriteLine(ret) ' メソッドの戻り値を表示する
+

          
+
    ' プロパティPに値42を設定する
+
    t.InvokeMember("P", BindingFlags.SetProperty, Nothing, inst, New Object() {42})
+

          
+
    ' プロパティPの値を取得する
+
    Dim p As Object = t.InvokeMember("P", BindingFlags.GetProperty, Nothing, inst, Nothing)
+

          
+
    Console.WriteLine("P = {0}", p)
+

          
+
    ' フィールドFに値3.14を設定する
+
    t.InvokeMember("F", BindingFlags.SetField, Nothing, inst, New Object() {3.14})
+

          
+
    ' フィールドFの値を取得する
+
    Dim f As Object = t.InvokeMember("F", BindingFlags.GetField, Nothing, inst, Nothing)
+

          
+
    Console.WriteLine("F = {0}", f)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
HELLO, WORLD!
+
P = 42
+
F = 3.14
+
}}
+

          
+
#tabpage(codelang=cs,container-title=Type.InvokeMemberを使ってインスタンスの作成を行う例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  private string str = "Hello, world!";
+

          
+
  public C()
+
  {
+
  }
+

          
+
  public C(string str)
+
  {
+
    this.str = str;
+
  }
+

          
+
  public override string ToString()
+
  {
+
    return str;
+
  }
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    Type t = typeof(C);
+

          
+
    object inst;
+

          
+
    // コンストラクタに渡す引数を指定せずにインスタンスを作成する
+
    // (引数のないコンストラクタを使ってインスタンスを作成する)
+
    inst = t.InvokeMember(null, BindingFlags.CreateInstance, null, null, null);
+

          
+
    Console.WriteLine(inst);
+

          
+
    // コンストラクタに渡す引数を指定してインスタンスを作成する
+
    // (引数のあるコンストラクタを使ってインスタンスを作成する)
+
    inst = t.InvokeMember(null, BindingFlags.CreateInstance, null, null, new object[] {"Hello, instance!"});
+

          
+
    Console.WriteLine(inst);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C
+
  Private str As String = "Hello, world!"
+

          
+
  Public Sub New()
+
  End Sub
+

          
+
  Public Sub New(ByVal str As String)
+
    Me.str = str
+
  End Sub
+

          
+
  Public Overrides Function ToString() As String
+
    Return str
+
  End Function
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t As Type = GetType(C)
+

          
+
    Dim inst As Object
+

          
+
    ' コンストラクタに渡す引数を指定せずにインスタンスを作成する
+
    ' (引数のないコンストラクタを使ってインスタンスを作成する)
+
    inst = t.InvokeMember(Nothing, BindingFlags.CreateInstance, Nothing, Nothing, Nothing)
+

          
+
    Console.WriteLine(inst)
+

          
+
    ' コンストラクタに渡す引数を指定してインスタンスを作成する
+
    ' (引数のあるコンストラクタを使ってインスタンスを作成する)
+
    inst = t.InvokeMember(Nothing, BindingFlags.CreateInstance, Nothing, Nothing, New Object() {"Hello, instance!"})
+

          
+
    Console.WriteLine(inst)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Hello, world!
+
Hello, instance!
+
}}
+

          
+

          
+
***MemberInfo [#MemberInfo_Invoke]
+
MethodInfoやPropertyInfoを取得し、以下のメソッドを使うことでもメンバの呼び出しを行うことができます。 MethodInfoやPropertyInfoの取得には[[GetMethodやGetPropertyなどのメソッド>#Type.GetMembers]]を使用します。
+

          
+
|*メンバの呼び出しを行うメソッド
+
|~メソッド|~動作|h
+
|&msdn(netfx,member,System.Reflection.MethodInfo.Invoke){MethodInfo.Invoke};|指定した引数と一致するメソッドを呼び出して戻り値を取得する|
+
|&msdn(netfx,member,System.Reflection.PropertyInfo.SetValue){PropertyInfo.SetValue};|プロパティに値を設定する|
+
|&msdn(netfx,member,System.Reflection.PropertyInfo.GetValue){PropertyInfo.GetValue};|プロパティの値を取得する|
+
|&msdn(netfx,member,System.Reflection.FieldInfo.SetValue){FieldInfo.SetValue};|フィールドに値を設定する|
+
|&msdn(netfx,member,System.Reflection.FieldInfo.GetValue){FieldInfo.GetValue};|フィールドの値を取得する|
+
|&msdn(netfx,member,System.Reflection.ConstructorInfo.Invoke){ConstructorInfo.Invoke};|指定した引数と一致するコンストラクタを呼び出してインスタンスを作成する|
+

          
+
[[Type.InvokeMemberメソッド>#Type.InvokeMember]]と同様、操作の対象となるインスタンスを引数で指定します。 また、メソッドおよびコンストラクタの呼び出し時に渡す引数は``object``型の配列に格納して指定します。 フィールド・プロパティに設定する値を``object``型の配列に格納して指定するInvokeMemberメソッドとは異なり、PropertyInfo.SetValueメソッド・FieldInfo.SetValueメソッドでは設定する値を直接引数として指定します。
+

          
+
#tabpage(codelang=cs,container-title=MemberInfoを使ってメンバの呼び出しを行う例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  public string M(string s)
+
  {
+
    return s.ToUpper();
+
  }
+

          
+
  public double F = 0.0;
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    Type t = typeof(C);
+

          
+
    object inst = Activator.CreateInstance(t);
+

          
+
    // メソッドMのMethodInfoを取得する
+
    MethodInfo m = t.GetMethod("M");
+

          
+
    // メソッドを呼び出す
+
    object ret = m.Invoke(inst, new object[] {"Hello, world!"});
+

          
+
    Console.WriteLine(ret); // メソッドの戻り値を表示する
+

          
+
    // フィールドFのFieldInfoを取得する
+
    FieldInfo f = t.GetField("F");
+

          
+
    // フィールドに値3.14を設定する
+
    f.SetValue(inst, 3.14);
+

          
+
    // フィールドの値を取得する
+
    Console.WriteLine("F = {0}", f.GetValue(inst));
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C
+
  Public Function M(ByVal s As String) As String
+
    Return s.ToUpper()
+
  End Function
+

          
+
  Public F As Double = 0.0
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t As Type = GetType(C)
+

          
+
    Dim inst As Object = Activator.CreateInstance(t)
+

          
+
    ' メソッドMのMethodInfoを取得する
+
    Dim m As MethodInfo = t.GetMethod("M")
+

          
+
    ' メソッドを呼び出す
+
    Dim ret As Object = m.Invoke(inst, New Object() {"Hello, world!"})
+

          
+
    Console.WriteLine(ret) ' メソッドの戻り値を表示する
+

          
+
    ' フィールドFのFieldInfoを取得する
+
    Dim f As FieldInfo = t.GetField("F")
+

          
+
    ' フィールドに値3.14を設定する
+
    f.SetValue(inst, 3.14)
+

          
+
    ' フィールドの値を取得する
+
    Console.WriteLine("F = {0}", f.GetValue(inst))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
HELLO, WORLD!
+
F = 3.14
+
}}
+

          
+
これらのメソッドでは、メンバの呼び出しを行うインスタンスや設定する値はすべて``object``型の引数に渡します。 これにより構造体など値型インスタンスのフィールド・プロパティを設定する際には問題が生じる場合がありますが、この問題と回避方法に関しては[[programming/netfx/tips/set_struct_field_using_reflection]]で解説しているので、合わせてご覧ください。
+

          
+

          
+
****MethodInfoを使ったメソッド呼び出し [#MethodInfo.Invoke]
+
*****ref/ByRefパラメータ
+
メソッドの引数に``out``/``ref``修飾子、``ByRef``修飾子が設定されている場合、引数は参照渡しとなり別の値に置き換えることができます。 MethodInfo.Invokeメソッドを使ってメソッドを呼び出す場合、参照渡しによって置き換えられた値は引数&var{parameters};に渡した配列に格納されます。
+

          
+
#tabpage(codelang=cs,container-title=参照渡しの引数を参照する例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  public void M(int x, ref int y)
+
  {
+
    Console.WriteLine("x = {0}", x);
+
    Console.WriteLine("y = {0}", y);
+

          
+
    x = 3;
+
    y = 3;
+
  }
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    Type t = typeof(C);
+

          
+
    object inst = Activator.CreateInstance(t);
+

          
+
    MethodInfo m = t.GetMethod("M");
+

          
+
    // メソッド呼び出しに使用する引数の配列
+
    object[] args = new object[2] {42, 42};
+

          
+
    m.Invoke(inst, args);
+

          
+
    // 置き換えられた値を参照する
+
    Console.WriteLine(args[0]);
+
    Console.WriteLine(args[1]);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C
+
  Public Sub M(ByVal x As Integer, ByRef y As Integer)
+
    Console.WriteLine("x = {0}", x)
+
    Console.WriteLine("y = {0}", y)
+

          
+
    x = 3
+
    y = 3
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t As Type = GetType(C)
+

          
+
    Dim inst As Object = Activator.CreateInstance(t)
+

          
+
    Dim m As MethodInfo = t.GetMethod("M")
+

          
+
    ' メソッド呼び出しに使用する引数の配列
+
    Dim args() As Object = New Object(1) {42, 42}
+

          
+
    m.Invoke(inst, args)
+

          
+
    ' 置き換えられた値を参照する
+
    Console.WriteLine(args(0))
+
    Console.WriteLine(args(1))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
x = 42
+
y = 42
+
42
+
3
+
}}
+

          
+

          
+
*****例外
+
MethodInfo.Invokeメソッドによって呼び出したメソッドが例外をスローした場合、&msdn(netfx,type,System.Reflection.TargetInvocationException){TargetInvocationException};がスローされます。 呼び出したメソッド内で発生した例外はTargetInvocationExceptionにラップされるため、実際にメソッドがスローした例外はInnerExceptionプロパティを参照することで取得することができます。
+

          
+
#tabpage(codelang=cs,container-title=メソッドがスローした例外を取得する例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  public void M()
+
  {
+
    throw new NotImplementedException();
+
  }
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    Type t = typeof(C);
+

          
+
    object inst = Activator.CreateInstance(t);
+

          
+
    MethodInfo m = t.GetMethod("M");
+

          
+
    try {
+
      m.Invoke(inst, null);
+
    }
+
    // 呼び出したメソッドで例外が発生した場合、TargetInvocationExceptionがスローされる
+
    catch (TargetInvocationException ex) {
+
      // メソッドがスローした例外を取得する
+
      Console.WriteLine(ex.InnerException);
+
    }
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C
+
  Public Sub M()
+
    Throw New NotImplementedException()
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t As Type = GetType(C)
+

          
+
    Dim inst As Object = Activator.CreateInstance(t)
+

          
+
    Dim m As MethodInfo = t.GetMethod("M")
+

          
+
    Try
+
      m.Invoke(inst, Nothing)
+
    Catch ex As TargetInvocationException
+
      ' 呼び出したメソッドで例外が発生した場合、TargetInvocationExceptionがスローされる
+

          
+
      ' メソッドがスローした例外を取得する
+
      Console.WriteLine(ex.InnerException)
+
    End Try
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
System.NotImplementedException: メソッドまたは操作は実装されていません。
+
   場所 C.M()
+
}}
+

          
+
[[PropertyInfo.GetValue/SetValue>#PropertyInfo.GetValue]]および[[ConstructorInfo.Invoke>#ConstructorInfo.Invoke]]によってプロパティ・コンストラクタを呼び出した結果例外が発生した場合も同様にTargetInvocationExceptionがスローされます。
+

          
+

          
+

          
+
****PropertyInfoを使ったプロパティ・インデクサの操作 [#PropertyInfo.GetValue]
+
&msdn(netfx,member,System.Reflection.PropertyInfo.GetValue){PropertyInfo.GetValue};/&msdn(netfx,member,System.Reflection.PropertyInfo.SetValue){SetValueメソッド};を使うとプロパティの値の取得・設定を行うことができます。 インデクサ(既定のプロパティ、引数を持つプロパティ)に対する値の設定・取得もこのメソッドで行います。
+

          
+
.NET Framework 4.0以前の場合、PropertyInfo.GetValue/SetValueメソッドでは引数&var{obj};の他に引数&var{index};も指定する必要があります。 この引数はプロパティがインデクサの場合にインデックスとして使用される値を指定するためのものです。 プロパティがインデクサでない場合は引数&var{index};に``null``/``Nothing``を指定します。
+

          
+
.NET Framework 4.5以降では引数&var{index};を必要としないオーバーロードが用意されているため、インデクサではないプロパティではインデックスの指定を省略することができます。
+

          
+

          
+
#tabpage(codelang=cs,container-title=PropertyInfoを使ってプロパティの値を取得・設定する例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  public int P { get; set; }
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    Type t = typeof(C);
+

          
+
    object inst = Activator.CreateInstance(t);
+

          
+
    // プロパティPのPropertyInfoを取得する
+
    PropertyInfo p = t.GetProperty("P");
+

          
+
    // プロパティに値42を設定する
+
    p.SetValue(inst, 42); // .NET Framework 4.5以降の場合
+
    //p.SetValue(inst, 42, null); // .NET Framework 4.0以前の場合
+

          
+
    // プロパティの値を取得する
+
    Console.WriteLine("P = {0}", p.GetValue(inst)); // .NET Framework 4.5以降の場合
+
    //Console.WriteLine("P = {0}", p.GetValue(inst, null)); // .NET Framework 4.0以前の場合
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C
+
  Public Property P As Integer
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t As Type = GetType(C)
+

          
+
    Dim inst As Object = Activator.CreateInstance(t)
+

          
+
    ' プロパティPのPropertyInfoを取得する
+
    Dim p As PropertyInfo = t.GetProperty("P")
+

          
+
    ' プロパティに値42を設定する
+
    p.SetValue(inst, 42) ' .NET Framework 4.5以降の場合
+
    'p.SetValue(inst, 42, Nothing) ' .NET Framework 4.0以前の場合
+

          
+
    ' プロパティの値を取得する
+
    Console.WriteLine("P = {0}", p.GetValue(inst)) ' .NET Framework 4.5以降の場合
+
    'Console.WriteLine("P = {0}", p.GetValue(inst, Nothing)) ' .NET Framework 4.0以前の場合
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
P = 42
+
}}
+

          
+
以下はPropertyInfoを使ってインデクサの値を取得・設定する例です。 C#では特に指定しない場合はインデクサの名前は``Item``となりますが、&msdn(netfx,type,System.Runtime.CompilerServices.IndexerNameAttribute){IndexerName属性};によって変更可能である点に注意してください。
+

          
+
#tabpage(codelang=cs,container-title=PropertyInfoを使ってインデクサの値を取得・設定する例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  //[System.Runtime.CompilerServices.IndexerName("Item")]
+
  public int this[int index] {
+
    get { return arr[index]; }
+
    set { arr[index] = value; }
+
  }
+

          
+
  private int[] arr = new int[2];
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    C inst = new C();
+

          
+
    inst[0] = 42;
+
    inst[1] = 0;
+

          
+
    Type t = inst.GetType();
+

          
+
    // インデクサItemのPropertyInfoを取得する
+
    PropertyInfo p = t.GetProperty("Item");
+

          
+
    // インデクサのインデックス1に値3を設定する
+
    p.SetValue(inst, 3, new object[] {1});
+

          
+
    // インデクサからインデックス0と1の値を取得する
+
    Console.WriteLine(p.GetValue(inst, new object[] {0}));
+
    Console.WriteLine(p.GetValue(inst, new object[] {1}));
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C
+
  Public Default Property Item(ByVal index As Integer) As Integer
+
    Get
+
      Return arr(index)
+
    End Get
+
    Set(ByVal value As Integer)
+
      arr(index) = value
+
    End Set
+
  End Property
+

          
+
  Private arr(1) As Integer
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim inst As New C()
+

          
+
    inst(0) = 42
+
    inst(1) = 0
+

          
+
    Dim t As Type = inst.GetType()
+

          
+
    ' インデクサItemのPropertyInfoを取得する
+
    Dim p As PropertyInfo = t.GetProperty("Item")
+

          
+
    ' インデクサのインデックス1に値3を設定する
+
    p.SetValue(inst, 3, New Object() {1})
+

          
+
    ' インデクサからインデックス0と1の値を取得する
+
    Console.WriteLine(p.GetValue(inst, New Object() {0})) ' inst(0)
+
    Console.WriteLine(p.GetValue(inst, New Object() {1})) ' inst(1)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
42
+
3
+
}}
+

          
+
-関連
+
--[[programming/netfx/tips/set_struct_field_using_reflection]]
+

          
+
****ConstructorInfoを使ったインスタンスの作成 [#ConstructorInfo.Invoke]
+
以下はConstructorInfoを使ってコンストラクタを呼び出し、インスタンスを作成・初期化する例です。 ConstructorInfo.Invokeメソッドを呼び出す際にはインスタンスを指定する必要がない点、作成されたインスタンスは戻り値として返される点を除けば、MethodInfo.Invokeメソッドと変わりありません。
+

          
+
#tabpage(codelang=cs,container-title=ConstructorInfoを使ってインスタンスの作成を行う例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  private string str = "Hello, world!";
+

          
+
  public C()
+
  {
+
  }
+

          
+
  public C(string str)
+
  {
+
    this.str = str;
+
  }
+

          
+
  public override string ToString()
+
  {
+
    return str;
+
  }
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    Type t = typeof(C);
+

          
+
    object inst;
+

          
+
    // 引数を持たないコンストラクタのConstructorInfoを取得する
+
    ConstructorInfo c1 = t.GetConstructor(Type.EmptyTypes);
+

          
+
    // コンストラクタを呼び出してインスタンスを作成する
+
    inst = c1.Invoke(null);
+

          
+
    Console.WriteLine(inst);
+

          
+
    // string型の引数を1つとるコンストラクタのConstructorInfoを取得する
+
    ConstructorInfo c2 = t.GetConstructor(new Type[] {typeof(string)});
+

          
+
    // コンストラクタを呼び出してインスタンスを作成する
+
    inst = c2.Invoke(new object[] {"Hello, instance!"});
+

          
+
    Console.WriteLine(inst);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C
+
  Private str As String = "Hello, world!"
+

          
+
  Public Sub New()
+
  End Sub
+

          
+
  Public Sub New(ByVal str As String)
+
    Me.str = str
+
  End Sub
+

          
+
  Public Overrides Function ToString() As String
+
    Return str
+
  End Function
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t As Type = GetType(C)
+

          
+
    Dim inst As Object
+

          
+

          
+
    ' 引数を持たないコンストラクタのConstructorInfoを取得する
+
    Dim c1 As ConstructorInfo = t.GetConstructor(Type.EmptyTypes)
+

          
+
    ' コンストラクタを呼び出してインスタンスを作成する
+
    inst = c1.Invoke(Nothing)
+

          
+
    Console.WriteLine(inst)
+

          
+
    ' String型の引数を1つとるコンストラクタのConstructorInfoを取得する
+
    Dim c2 As ConstructorInfo = t.GetConstructor(New Type() {GetType(String)})
+

          
+
    ' コンストラクタを呼び出してインスタンスを作成する
+
    inst = c2.Invoke(New Object() {"Hello, instance!"})
+

          
+
    Console.WriteLine(inst)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Hello, world!
+
Hello, instance!
+
}}
+

          
+
****MethodInfoからデリゲートを取得する
+
&msdn(netfx,member,System.Delegate.CreateDelegate){Delegate.CreateDelegateメソッド};を使うとMethodInfoをデリゲートに変換することができ、デリゲートを介してメソッドの呼び出しを行えるようになります。
+

          
+
CreateDelegateメソッドの引数には、取得したいデリゲートの型を指定します。 デリゲートの型とMethodInfoが表すメソッドのシグネチャは一致している必要があります。 また、インスタンスメソッドの場合は呼び出し対象のインスタンスを指定します。 クラスメソッド(静的メソッド)の場合はインスタンスを指定する必要はありません。 CreateDelegateメソッドの戻り値は&msdn(netfx,type,System.Delegate){Delegate};なので、作成したデリゲートを呼び出す場合は適切な型にキャストしてから呼び出す必要があります。
+

          
+
#tabpage(codelang=cs,container-title=MethodInfoからデリゲートを取得する例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  public void M1(string s)
+
  {
+
    Console.WriteLine(s);
+
  }
+

          
+
  public static void M2(string s)
+
  {
+
    Console.WriteLine(s);
+
  }
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    C inst = new C();
+

          
+
    Type t = typeof(C);
+

          
+
    // インスタンスメソッドM1のMethodInfoからデリゲートを作成する
+
    MethodInfo m1 = t.GetMethod("M1");
+
    Action<string> a1 = (Action<string>)Delegate.CreateDelegate(typeof(Action<string>), inst, m1);
+

          
+
    a1("Hello, world!"); // 作成したデリゲートを介してメソッドを呼び出す
+

          
+
    // クラスメソッドM2のMethodInfoからデリゲートを作成する
+
    MethodInfo m2 = t.GetMethod("M2");
+
    Action<string> a2 = (Action<string>)Delegate.CreateDelegate(typeof(Action<string>), m2);
+

          
+
    a2("Hello, world!");
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C
+
  Public Sub M1(ByVal s As String)
+
    Console.WriteLine(s)
+
  End Sub
+

          
+
  Public Shared Sub M2(ByVal s As String)
+
    Console.WriteLine(s)
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim inst As New C()
+

          
+
    Dim t As Type = GetType(C)
+

          
+
    ' インスタンスメソッドM1のMethodInfoからデリゲートを作成する
+
    Dim m1 As MethodInfo = t.GetMethod("M1")
+
    Dim a1 As Action(Of String) = DirectCast([Delegate].CreateDelegate(GetType(Action(Of String)), inst, m1), Action(Of String))
+

          
+
    a1("Hello, world!") ' 作成したデリゲートを介してメソッドを呼び出す
+

          
+
    ' クラスメソッドM2のMethodInfoからデリゲートを作成する
+
    Dim m2 As MethodInfo = t.GetMethod("M2")
+
    Dim a2 As Action(Of String) = DirectCast([Delegate].CreateDelegate(GetType(Action(Of String)), m2), Action(Of String))
+

          
+
    a2("Hello, world!")
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Hello, world!
+
Hello, world!
+
}}
+

          
+

          
+
****デリゲートからMethodInfoを取得する
+
デリゲート型では&msdn(netfx,member,System.Delegate.Method){Methodプロパティ};を参照することで呼び出し対象となるメソッドのMethodInfoを取得することができます。
+

          
+
#tabpage(codelang=cs,container-title=デリゲートからMethodInfoを取得する例)
+
#code{{
+
using System;
+

          
+
class C {
+
  public void M1() {}
+
  public static void M2() {}
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    C inst = new C();
+

          
+
    // インスタンスメソッドM1のデリゲート
+
    Action a1 = (Action)inst.M1;
+

          
+
    // クラスメソッドM2のデリゲート
+
    Action a2 = (Action)C.M2;
+

          
+
    Console.WriteLine(a1.Method);
+
    Console.WriteLine(a2.Method);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class C
+
  Public Sub M1()
+
  End Sub
+

          
+
  Public Shared Sub M2()
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim inst As New C()
+

          
+
    ' インスタンスメソッドM1のデリゲート
+
    Dim a1 As New Action(AddressOf inst.M1)
+

          
+
    ' クラスメソッドM2のデリゲート
+
    Dim a2 As New Action(AddressOf C.M2)
+

          
+
    Console.WriteLine(a1.Method)
+
    Console.WriteLine(a2.Method)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Void M1()
+
Void M2()
+
}}
+

          
+
他のデリゲートと連結されたデリゲート(マルチキャストデリゲート)では、&msdn(netfx,member,System.MulticastDelegate.GetInvocationList){GetInvocationListメソッド};を使って連結されている個々のデリゲートを取得してからMethodプロパティを参照します。
+

          
+
#tabpage(codelang=cs,container-title=マルチキャストデリゲートからMethodInfoを取得する例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  public void M1() {}
+
  public static void M2() {}
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    C inst = new C();
+

          
+
    Action a = (Action)inst.M1;
+

          
+
    // デリゲートの連結
+
    a += C.M2;
+

          
+
    // 連結されたデリゲートから個々のデリゲートを列挙する
+
    foreach (Delegate d in a.GetInvocationList()) {
+
      Console.WriteLine(d.Method);
+
    }
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class C
+
  Public Sub M1()
+
  End Sub
+

          
+
  Public Shared Sub M2()
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim inst As New C()
+

          
+
    Dim a As New Action(AddressOf inst.M1)
+

          
+
    ' デリゲートの連結
+
    a = DirectCast([Delegate].Combine(a, New Action(AddressOf C.M2)), Action)
+

          
+
    ' 連結されたデリゲートから個々のデリゲートを列挙する
+
    For Each d As [Delegate] In a.GetInvocationList()
+
      Console.WriteLine(d.Method)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Void M1()
+
Void M2()
+
}}
+

          
+
デリゲートと呼び出されるメソッドに関しては[[programming/netfx/delegate/2_operations#invocationlist]]でも解説しています。
+

          
+

          
+
****EventInfoを使ったイベントの発行
+
EventInfoクラスにはイベントを発行するメソッドは用意されていません。 そのためイベント発行時の動作と同等の処理を独自に記述する必要があります。 EventInfoクラスからは以下のような手順をとることでイベントの発行を行うことができます。
+

          
+
+イベントハンドラのデリゲートを格納しているフィールドのFieldInfoを取得する
+
+取得したFieldInfoからイベントハンドラを格納している&msdn(netfx,type,System.MulticastDelegate){MulticastDelegate};を取得する
+
+&msdn(netfx,member,System.MulticastDelegate.GetInvocationList){MulticastDelegate.GetInvocationListメソッド};を使ってイベントハンドラとして割り当てられているメソッドのリスト(MethodInfoの配列)を取得する
+
+取得したMethodInfoひとつずつに対してメソッドの呼び出しを行う
+

          
+
C#とVBでは''イベントハンドラを格納しているフィールド名が異なる''点に注意が必要です。 例えばイベント名が``Click``の場合、C#ではフィールド``Click``、VBではフィールド``ClickEvent``にイベントハンドラが格納されます。
+

          
+
上記の処理を具体的に実装すると次のようになります。
+

          
+
#tabpage(codelang=cs,container-title=EventInfoを使ったイベントの発行を行う例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  public event EventHandler<EventArgs> E;
+
}
+

          
+
class Sample {
+
  static void Handler1(object sender, EventArgs e)
+
  {
+
    Console.WriteLine("Handler1");
+
  }
+

          
+
  static void Handler2(object sender, EventArgs e)
+
  {
+
    Console.WriteLine("Handler2");
+
  }
+

          
+
  public static void Main()
+
  {
+
    C inst = new C();
+

          
+
    // イベントEにハンドラを割り当てる
+
    inst.E += Handler1;
+
    inst.E += Handler2;
+

          
+
    // イベントEのEventInfoを取得する
+
    EventInfo ev = inst.GetType().GetEvent("E");
+

          
+
    // EventInfoを使ってイベントを発行する
+
    Raise(inst, ev, EventArgs.Empty);
+
  }
+

          
+
  static void Raise<TEventArgs>(object sender, EventInfo ev, TEventArgs e)
+
  {
+
    var f = sender.GetType().GetField(ev.Name, BindingFlags.Instance | BindingFlags.NonPublic);
+
    var handler = (MulticastDelegate)f.GetValue(sender);
+

          
+
    if (handler == null)
+
      return;
+

          
+
    foreach (var h in handler.GetInvocationList()) {
+
      h.Method.Invoke(h.Target, new object[] {sender, e});
+
    }
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C
+
  Public Event E As EventHandler(Of EventArgs)
+
End Class
+

          
+
Class Sample
+
  Shared Sub Handler1(ByVal sender As Object, ByVal e As EventArgs)
+
    Console.WriteLine("Handler1")
+
  End Sub
+

          
+
  Shared Sub Handler2(ByVal sender As Object, ByVal e As EventArgs)
+
    Console.WriteLine("Handler2")
+
  End Sub
+

          
+
  Public Shared Sub Main()
+
    Dim inst As New C()
+

          
+
    ' イベントEにハンドラを割り当てる
+
    AddHandler inst.E, AddressOf Handler1
+
    AddHandler inst.E, AddressOf Handler2
+

          
+
    ' イベントEのEventInfoを取得する
+
    Dim ev As EventInfo = inst.GetType().GetEvent("E")
+

          
+
    ' EventInfoを使ってイベントを発行する
+
    Raise(inst, ev, EventArgs.Empty)
+
  End Sub
+

          
+
  Shared Sub Raise(Of TEventArgs)(ByVal sender As Object, ByVal ev As EventInfo, ByVal e As TEventArgs)
+
    Dim f As FieldInfo = sender.GetType().GetField(ev.Name + "Event", BindingFlags.Instance Or BindingFlags.NonPublic)
+
    Dim handler As MulticastDelegate = DirectCast(f.GetValue(sender), MulticastDelegate)
+

          
+
    If handler Is Nothing Then Return
+

          
+
    For Each h As [Delegate] In handler.GetInvocationList()
+
      h.Method.Invoke(h.Target, New Object() {sender, e})
+
    Next
+
 End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Handler1
+
Handler2
+
}}
+

          
+
MulticastDelegate.GetInvocationListメソッドについては[[programming/netfx/delegate/2_operations#invocationlist]]で解説しています。
+

          
+
-参考
+
--[[How do I raise an event via reflection in .NET/C#? - Stack Overflow:http://stackoverflow.com/questions/198543/how-do-i-raise-an-event-via-reflection-in-net-c]]
+
--[[raising an event via reflection:https://social.msdn.microsoft.com/Forums/vstudio/en-US/44b0d573-5c53-47b0-8e85-6056cbae95b0/raising-an-event-via-reflection?forum=netfxbcl]]
+

          
+

          
+
****静的コンストラクタの呼び出し
+
&msdn(netfx,member,System.Type.TypeInitializer){Type.TypeInitializerプロパティ};を参照すると静的コンストラクタ(クラスコンストラクタ)のConstructorInfoを取得することができます。 (``BindingFlags.Static``と``BindingFlags.NonPublic``を指定して[[GetConstructorメソッド>#Type.GetMembers]]を呼び出しても静的コンストラクタを取得することができます)
+

          
+
通常、静的コンストラクタは自動的に一度だけ呼び出されるのみで、ユーザーコードからは呼び出すことはできませんが、TypeInitializerプロパティから取得したConstructorInfoを使うことで静的コンストラクタを任意のタイミングで呼び出すことができます。
+

          
+
#tabpage(codelang=cs,container-title=静的コンストラクタを呼び出す例)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
class C {
+
  // 静的コンストラクタ
+
  static C()
+
  {
+
    Console.WriteLine("initialized");
+
  }
+
}
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    Type t = typeof(C);
+

          
+
    // 静的コンストラクタのConstructorInfoを取得する
+
    ConstructorInfo cctor = t.TypeInitializer;
+

          
+
    Console.WriteLine(cctor);
+

          
+
    // 静的コンストラクタを呼び出す
+
    cctor.Invoke(null, null);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
Class C
+
  ' 静的コンストラクタ
+
  Shared Sub New()
+
    Console.WriteLine("initialized")
+
  End Sub
+
End Class
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim t As Type = GetType(C)
+

          
+
    ' 静的コンストラクタのConstructorInfoを取得する
+
    Dim cctor As ConstructorInfo = t.TypeInitializer
+

          
+
    Console.WriteLine(cctor)
+

          
+
    ' 静的コンストラクタを呼び出す
+
    cctor.Invoke(Nothing, Nothing)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Void .cctor()
+
initialized
+
initialized
+
}}
+

          
+
実行結果からも分かるとおり、静的コンストラクタが自動的に呼び出された分と、ConstructorInfoを使って呼び出した分の二回分が表示されています。 つまり、ConstructorInfoを使って静的コンストラクタを呼び出したことにより、クラスが再初期化されたことになります。
+

          
+
ほとんどの場合、このような最初期化を行う必要性はありません。 また静的コンストラクタは一度だけ呼び出されることを前提としていることから、静的コンストラクタを最初の初期化以外で呼び出すことはクラスの状態を破壊する可能性もあるため、推奨されません。
+

          
+

          
+
*動的な生成
+
**System.Reflection.Emit
+
&msdn(netfx,ns,System.Reflection.Emit){System.Reflection.Emit名前空間};の&msdn(netfx,type,System.Reflection.Emit.TypeBuilder){TypeBuilder};や&msdn(netfx,type,System.Reflection.Emit.MethodBuilder){MethodBuilder};などのクラスを使うと型情報やメソッドの実装を動的に生成し、実行することができます。 ただし、メソッドの実装には&msdn(netfx,type,System.Reflection.Emit.ILGenerator){ILGeneratorクラス};を使って''ILコード''(intermediate language, 中間言語コード)を記述する必要があるため、ILに関する知識が必要となります。
+

          
+
以下の例ではSystem.Reflection.Emit名前空間のクラスを使って以下のようなクラスを動的に生成し、作成したクラスのメソッドを呼び出しています。
+

          
+
#tabpage(codelang=cs,container-title=生成されるクラスのイメージ)
+
#code{{
+
public class HelloWorld {
+
  public void Print()
+
  {
+
    Console.WriteLine("Hello, world!");
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Public Class HelloWorld
+
  Public Sub Print()
+
    Console.WriteLine("Hello, world!")
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#tabpage(codelang=cs,container-title=System.Reflection.Emit名前空間のクラスを使って動的にクラスとメソッドを生成する例)
+
#code{{
+
using System;
+
using System.Reflection;
+
using System.Reflection.Emit;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    // アセンブリ名"DynamicAssmembly"で動的にアセンブリを生成する
+
    AssemblyName assmName = new AssemblyName("DynamicAssmembly");
+

          
+
    AssemblyBuilder assm = AppDomain.CurrentDomain.DefineDynamicAssembly(assmName, AssemblyBuilderAccess.Run);
+

          
+
    // 作成したアセンブリ内にモジュールを宣言する
+
    ModuleBuilder module = assm.DefineDynamicModule("DynamicModule");
+

          
+
    // 作成したモジュール内にクラス(object型を基底クラスとした型)を宣言する
+
    TypeBuilder type = module.DefineType("HelloWorld", TypeAttributes.Public, typeof(object));
+

          
+
    // 作成したクラス内に戻り値がvoid(なし)、引数なしのパブリックメソッドを宣言する
+
    MethodBuilder method = type.DefineMethod("Print", MethodAttributes.Public, typeof(void), Type.EmptyTypes);
+

          
+
    // メソッドの実装となるILコードを生成する
+
    ILGenerator generator = method.GetILGenerator();
+

          
+
    generator.Emit(OpCodes.Ldstr, "Hello, world!");
+
    generator.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] {typeof(string)}));
+
    generator.Emit(OpCodes.Ret);
+

          
+
    // 生成した型情報を使ってインスタンスを作成し、メソッドを呼び出す
+
    Type t = type.CreateType();
+

          
+
    object inst = Activator.CreateInstance(t);
+

          
+
    t.InvokeMember("Print", BindingFlags.InvokeMethod, null, inst, null);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+
Imports System.Reflection.Emit
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ' アセンブリ名"DynamicAssmembly"で動的にアセンブリを生成する
+
    Dim assmName As New AssemblyName("DynamicAssmembly")
+

          
+
    Dim assm As AssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assmName, AssemblyBuilderAccess.Run)
+

          
+
    ' 作成したアセンブリ内にモジュール(VBのModuleではない)を宣言する
+
    Dim mdl As ModuleBuilder = assm.DefineDynamicModule("DynamicModule")
+

          
+
    ' 作成したモジュール内にクラス(object型を基底クラスとした型)を宣言する
+
    Dim typ As TypeBuilder = mdl.DefineType("HelloWorld", TypeAttributes.Public, GetType(Object))
+

          
+
    ' 作成したクラス内に戻り値がvoid(なし)、引数なしのパブリックメソッドを宣言する
+
    Dim method As MethodBuilder = typ.DefineMethod("Print", MethodAttributes.Public, GetType(Void), Type.EmptyTypes)
+

          
+
    ' メソッドの実装となるILコードを生成する
+
    Dim generator As ILGenerator = method.GetILGenerator()
+

          
+
    generator.Emit(OpCodes.Ldstr, "Hello, world!")
+
    generator.Emit(OpCodes.Call, GetType(Console).GetMethod("WriteLine", New Type() {GetType(String)}))
+
    generator.Emit(OpCodes.Ret)
+

          
+
    ' 生成した型情報を使ってインスタンスを作成し、メソッドを呼び出す
+
    Dim t As Type = typ.CreateType()
+

          
+
    Dim inst As Object = Activator.CreateInstance(t)
+

          
+
    t.InvokeMember("Print", BindingFlags.InvokeMethod, Nothing, inst, Nothing)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Hello, world!
+
}}
+

          
+
**System.Linq.Expressions
+
&msdn(netfx,ns,System.Linq.Expressions){System.Linq.Expressions名前空間};のクラスを使って''式木''(expression tree, 式ツリーとも)を作成することによっても実行可能なコードを動的に生成することができます。 .NET Framework 4以降では、式だけでなく条件分岐やループなどのブロック構文も扱うことができるようになっています。 式木では生成したコードをデリゲートに変換(コンパイル)し、任意に呼び出すことができます。
+

          
+
#tabpage(codelang=cs,container-title=式木の例1)
+
#code{{
+
using System;
+
using System.Linq.Expressions;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    // 以下のラムダ式と同様の式木を生成する
+
    // Action<string> a = s => Console.WriteLine(s.ToUpper());
+

          
+
    // 式木に渡されるパラメータ(string型)
+
    var s = Expression.Parameter(typeof(string), "s");
+

          
+
    // Console.WriteLine(param.ToUpper())に相当する式木を生成する
+
    var printUpperCase = Expression.Call(
+
      typeof(Console).GetMethod("WriteLine", new[] {typeof(string)}),
+
      Expression.Call(s, typeof(string).GetMethod("ToUpper", Type.EmptyTypes))
+
    );
+

          
+
    // 式木を構成してラムダ式に変換する
+
    var lambda = Expression.Lambda<Action<string>>(printUpperCase, new[] {s});
+

          
+
    // デリゲートに変換する
+
    var a = lambda.Compile();
+

          
+
    // 変換したデリゲートに引数を渡して呼び出す
+
    a("Hello, world!");
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Option Infer On
+

          
+
Imports System
+
Imports System.Linq.Expressions
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ' 以下のラムダ式と同様の式木を生成する
+
    'Dim a As Action(Of String) = Sub(s) Console.WriteLine(s.ToUpper())
+

          
+
    ' 式木に渡されるパラメータ(string型)
+
    Dim s = Expression.Parameter(GetType(String), "s")
+

          
+
    ' Console.WriteLine(param.ToUpper())に相当する式木を生成する
+
    Dim printUpperCase = Expression.Call(
+
      GetType(Console).GetMethod("WriteLine", New Type() {GetType(String)}),
+
      Expression.Call(s, GetType(String).GetMethod("ToUpper", Type.EmptyTypes))
+
    )
+

          
+
    ' 式木を構成してラムダ式に変換する
+
    Dim lambda = Expression.Lambda(Of Action(Of String))(printUpperCase, New ParameterExpression() {s})
+

          
+
    ' デリゲートに変換する
+
    Dim a = lambda.Compile()
+

          
+
    ' 変換したデリゲートに引数を渡して呼び出す
+
    a("Hello, world!")
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Hello, world!
+
}}
+

          
+
#tabpage(codelang=cs,container-title=式木の例2)
+
#code{{
+
using System;
+
using System.Linq.Expressions;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    // 以下のラムダ式と同様の式木を生成する
+
    /*
+
    Func<int, int> f = n => {
+
      int sum = 0;
+
      for (;;) {
+
        if (n <= 0)
+
          break;
+
        sum += n;
+
        n -= 1;
+
      }
+
      return sum;
+
    };
+
    */
+

          
+
    var n = Expression.Parameter(typeof(int), "n");
+
    var sum = Expression.Parameter(typeof(int), "sum");
+
    var brk = Expression.Label("break");
+

          
+
    var body = Expression.Block(typeof(int), new[] {sum},
+
      Expression.Assign(sum, Expression.Constant(0)),
+
      Expression.Loop(
+
        Expression.Block(
+
          Expression.IfThen(
+
            Expression.LessThanOrEqual(n, Expression.Constant(0)),
+
            Expression.Break(brk)
+
          ),
+
          Expression.AddAssign(sum, n),
+
          Expression.SubtractAssign(n, Expression.Constant(1))
+
        ),
+
        brk
+
      ),
+
      sum
+
    );
+

          
+
    var lambda = Expression.Lambda<Func<int, int>>(body, new[] {n});
+

          
+
    var f = lambda.Compile();
+

          
+
    Console.WriteLine(f(0));
+
    Console.WriteLine(f(1));
+
    Console.WriteLine(f(2));
+
    Console.WriteLine(f(3));
+
    Console.WriteLine(f(4));
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Option Infer On
+

          
+
Imports System
+
Imports System.Linq.Expressions
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ' 以下のラムダ式と同様の式木を生成する
+
    'Dim f As Func(Of Integer, Integer) = Function(n)
+
    '  Dim sum As Integer = 0
+
    '  Do
+
    '    If n <= 0 Then Exit Do
+
    '    sum += n
+
    '    n -= 1
+
    '  Loop
+
    '  Return sum
+
    'End Function
+

          
+
    Dim n = Expression.Parameter(GetType(Integer), "n")
+
    Dim sum = Expression.Parameter(GetType(Integer), "sum")
+
    Dim brk = Expression.Label("break")
+

          
+
    Dim body = Expression.Block(GetType(Integer), New ParameterExpression() {sum},
+
      Expression.Assign(sum, Expression.Constant(0)),
+
      Expression.Loop(
+
        Expression.Block(
+
          Expression.IfThen(
+
            Expression.LessThanOrEqual(n, Expression.Constant(0)),
+
            Expression.Break(brk)
+
          ),
+
          Expression.AddAssign(sum, n),
+
          Expression.SubtractAssign(n, Expression.Constant(1))
+
        ),
+
        brk
+
      ),
+
      sum
+
    )
+

          
+
    Dim lambda = Expression.Lambda(Of Func(Of Integer, Integer))(body, New ParameterExpression() {n})
+

          
+
    Dim f = lambda.Compile()
+

          
+
    Console.WriteLine(f(0))
+
    Console.WriteLine(f(1))
+
    Console.WriteLine(f(2))
+
    Console.WriteLine(f(3))
+
    Console.WriteLine(f(4))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
0
+
1
+
3
+
6
+
10
+
}}
+

          
+

          
+
//*TODO
+
//オプショナルな引数
+
//拡張メソッド
+

          
+

          
+