VB.NET リフレクション
(Visual Studio 2015 版)

投稿日 2016/04/20

[Home] 

概要

リフレクションとはオブジェクトのメタ情報にアクセスして利用するものです。例えば、あるクラスのメンバー一覧を取得したり、メソッドの名前を文字列で指定して実行したりするとき使用します。

.NET では System.Reflection 名前空間のクラスを利用するとこのようなことが可能です。

 

Type オブジェクトを利用する場合

GetType 演算子と GetType() メソッド

クラスやそのインスタンスから Type オブジェクトを取得すると、クラスのメタ情報を取得できます。

クラスから Type オブジェクトを得るには GetType 演算子を使用します。

t As Type = GetType(System.Int32)

一方、クラスのインスタンスから Type オブジェクトを得るには、GetType() メソッドを利用します。

Dim obj As New Class1
Dim t As Type = obj.GetType()

メンバー情報を取得する

Type オブジェクトからクラスのメンバー情報一覧(配列)を取得できます。それには GetMembers() メソッドを使用します。メンバー情報は System.Reflection.MemberInfo クラスのインスタンスです。

Dim members As MemberInfo() = t.GetMembers()

メンバーの名前と種別はそれぞれ Name プロパティ、MemberType プロパティで取得できます。MemberType はメソッドやプロパティ、フィールドなどを識別するのに使用します。例えば、メソッドなら MemberTypes.Method という値になります。

メンバーの名前と種別がわかると、そのメンバーのオブジェクトを取得できます。例えば、メソッドの場合は Type.GetMethod() メソッドにより MethodInfo オブジェクトを取得できます。

Dim m As MethodInfo = t.GetMethod(member.Name)

メンバーの使用

MethodInfoには、Invoke() というメソッドがあって、これを使うとそのメソッドを実行できます。

m.Invoke(device, Nothing)

下のサンプルはプログラム DeviceClass というクラスをリフレクションを使って利用するものです。

Imports System.Reflection

Module ModMain
    ''' <summary>
    ''' メインプログラム
    ''' </summary>
    Sub Main()
        ' テスト対象のオブジェクト
        Dim device As New DeviceClass

        ' Type オブジェクトの取得
        Dim t As Type = GetType(DeviceClass)  ' GetType 演算子を用いてクラス名から Type オブジェクトを取得する。
        Dim t1 As Type = device.GetType()  ' GetType() メソッドを用いてオブジェクトから Type オブジェクトを取得する。
        Debug.Assert(t1.Equals(t))  ' どちらも同じであることを確認する。

        ' Type オブジェクトから対象のオブジェクトのメンバー一覧を取得する。
        Dim members As MemberInfo() = t.GetMembers()

        ' メンバー一覧から個別のメンバーを取得する。
        For Each member As MemberInfo In members
            ' メンバーの名前と種別を表示する。
            Console.WriteLine("{0} {1}", member.Name, member.MemberType)
            If member.MemberType = MemberTypes.Field Then
                ' フィールドメンバーの場合、FieldInfo オブジェクトを取得する。
                Dim f As FieldInfo = t.GetField(member.Name)
                If f.IsPublic AndAlso f.FieldType = GetType(System.String) Then
                    ' メンバーが Public かつ文字列なら値を変更する。
                    f.SetValue(device, "????")
                    Console.WriteLine(f.GetValue(device))  ' その値を確認
                End If
            ElseIf member.MemberType = MemberTypes.Method Then
                ' メソッドの場合、
                Dim m As MethodInfo = t.GetMethod(member.Name)
                Console.WriteLine(m.Name)
                If m.Name = "Clear" Then
                    ' Clear() を呼び出す。
                    Console.WriteLine("device.Clear()")
                    m.Invoke(device, Nothing)
                ElseIf m.Name = "set_Version" Then
                    ' set_Version を呼び出す。
                    m.Invoke(device, {"1.2.3.4"})
                End If
            ElseIf member.MemberType = MemberTypes.Property Then
                ' プロパティの場合
                Dim p As PropertyInfo = t.GetProperty(member.Name)
                Console.WriteLine(p.Name)
                If p.CanWrite And p.Name = "DeviceName" Then
                    ' プロパティのセットとゲット
                    p.SetValue(device, "MK01")
                    Console.WriteLine(p.GetValue(device))
                End If
                ' Clear() メソッドの結果を表示
                Console.WriteLine("{0},{1},{2},{3}", device.DeviceName, device.Version, device.DeviceType, device.Flag)
            Else

            End If
        Next

        Console.WriteLine("device.defaultValue = " & device.defaultValue)
#If DEBUG Then
        Console.WriteLine("終わり。何かキーを押してください。")
        Console.ReadKey()
#End If
    End Sub

    ''' <summary>
    ''' テスト対象のクラス
    ''' </summary>
    Class DeviceClass
        Private _deviceName As String
        Private _version As String
        Private _deviceType As String
        Private _flag As Integer

        Public defaultValue As String = ""
        Public Const C0 = 0

        Public Property DeviceName As String
            Get
                Return _deviceName
            End Get
            Set(value As String)
                _deviceName = value
            End Set
        End Property

        Public Property Version As String
            Get
                Return _version
            End Get
            Set(value As String)
                _version = value
            End Set
        End Property

        Public Property DeviceType As String
            Get
                Return _deviceType
            End Get
            Set(value As String)
                _deviceType = value
            End Set
        End Property

        Public Property Flag As Integer
            Get
                Return _flag
            End Get
            Set(value As Integer)
                _flag = value
            End Set
        End Property

        Public Sub Clear()
            _deviceName = defaultValue
            _version = defaultValue
            _deviceType = defaultValue
            _flag = C0
        End Sub
    End Class
End Module

 

アセンブリを利用する場合

リフレクションはアセンブリを元にして利用することもできます。まず、Assembly クラスの Load や LoadFile メソッドを利用して Assembly オブジェクトを取得します。

Dim asm As Assembly = Assembly.LoadFile(WORKDIR & "\bin\Debug\Library.dll")

アセンブリに含まれる Type オブジェクト一覧は GetTypes() メソッドで取得できます。このメソッドの戻り値は配列なので、目的の Type オブジェクトを見つけます。

Dim ts As Type() = asm.GetTypes()
If ts(0).Name = "DeviceClass" Then
   ...
End If

目的の Type オブジェクトが特定できると、Activator.CreateInstance() メソッドを使ってそのオブジェクトを作成して Type.Invoke() メソッドのパラメータとして使用することにより、メソッドやプロパティを利用できます。

次のサンプルは DeviceClass というクラスが含まれるアセンブリ (DLL) をロードして、利用するものです。

Imports System.Reflection
Imports LibraryForTest

Module ModMain
    ''' <summary>
    ''' メインプログラム
    ''' </summary>
    Sub Main()
        Const WORKDIR = "C:\workspace\project2015\ReflectionTest\LibraryForTest"
        ' アセンブリを読み込む。
        Dim asm As Assembly = Assembly.LoadFile(WORKDIR & "\bin\Debug\LibraryForTest.dll")
        Console.WriteLine(asm.FullName)
        Console.WriteLine("カスタム属性一覧")
        PrintEach(asm.CustomAttributes)
        ' Type オブジェクトを取得する。
        Dim ts As Type() = asm.GetTypes()
        PrintEach(ts)
        ' インスタンスを取得する。(アセンブリに1つのクラスしか定義していない場合)
        If ts(0).Name = "DeviceClass" Then
            Dim str As String
            Dim obj = Activator.CreateInstance(ts(0))
         ts(0).InvokeMember("DeviceName", BindingFlags.SetProperty, Nothing, obj, {"DEVICE 101"})
            str = ts(0).InvokeMember("DeviceName", BindingFlags.GetProperty, Nothing, obj, {})
            Console.WriteLine(str)
        End If

#If DEBUG Then
        Console.WriteLine("終わり。何かキーを押してください。")
        Console.ReadKey()
#End If
    End Sub

    ''' <summary>
    ''' 列挙可能なオブジェクトの要素をすべて表示する。
    ''' </summary>
    ''' <param name="col">コレクション</param>
    Sub PrintEach(ByVal col As IEnumerable)
        Dim e = col.GetEnumerator()
        While e.MoveNext()
            Console.WriteLine(e.Current)
        End While
    End Sub
End Module




 

 


 

 開設 2014年12月   著作権 2014-2015 bonk.red  連絡先: こちらからメッセージを送ってください。

 このページの先頭へ..