技术积累

明日复明日,明日何其多,我生待明日,万事成蹉跎。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

通过例子,浅谈反射(Reflection)的应用

Posted on 2005-07-25 12:34  追风逐云.NET  阅读(444)  评论(0编辑  收藏  举报

说明:

应该说这篇短文根本算不上什么深入的分析性的文章,所以在标题前加上了“浅谈”二字,希望对于一般的读者来说,可以给你一个相对直观些的对反射的认识。

                                                             --2005/05/23 于东莞

在这里对反射以及反射的概念在最后给出简要的解释。

一.用来测试的程序集文件的建立。

首先你需要建立一个类库文件(编译后扩展名为.dll),名字假设为:reflection_newtest

系统会默认地新建一个类文件class1,把它该成我们用来测试的类person

具体代码如下:(类的代码比较简单,这里不做解释,如有不明之处,请查看类的相关文档.)

Public Class person

    Public firstname As String

    Public lastname As String

    Dim m_age As Short

    Dim m_emailaddress(4) As String

    Public Sub New()

    Public Sub New()

    Public Sub New()

        MyBase.new()

    End Sub

    Public Sub New(ByVal firstname As String, ByVal lastname As String)

    Public Sub New(ByVal firstname As String, ByVal lastname As String)

    Public Sub New(ByVal firstname As String, ByVal lastname As String)

        Me.firstname = firstname

        Me.lastname = lastname

    End Sub

    Public Property age() As Short

    Public Property age() As Short

    Public Property age() As Short

        Get

            Return m_age

        End Get

        Set(ByVal Value As Short)

            m_age = Value

        End Set

    End Property

    Public Property emailaddress(ByVal index As Short) As String

        Get

            Return m_emailaddress(index)

        End Get

        Set(ByVal Value As String)

            m_emailaddress(index) = Value

        End Set

    End Property

    Sub sendemail(ByVal msg As String, Optional ByVal priorty As Integer = 1)

        Console.WriteLine("message to " & firstname & " " & lastname)

        Console.WriteLine("priority  " & priorty.ToString)

        Console.WriteLine(msg)

    End Sub

End Class

 二.测试验证的程序

 二.测试验证的程序

 二.测试验证的程序

建立一个winform的程序,命名假设为:testreflection

从工具栏里拖两个按钮,命名为button1,button2.

1.在程序的最上面加入引用:

Imports System

Imports System.Reflection

Imports System.Type

2.在button1click事件里写:

 Dim asm As [Assembly] 由于assembly是关键字,所以要加[]

 Dim asm As [Assembly] 由于assembly是关键字,所以要加[]

 Dim asm As [Assembly] 由于assembly是关键字,所以要加[]

        asm = Reflection.Assembly.LoadFrom("G:\练习\reflection_newtest\bin\reflection_newtest.dll") 这里假设上面的reflection_newtest文件的位置在G:\练习 的文件夹。

        Console.WriteLine(asm.FullName) ‘输出完全限定名

        Console.WriteLine(asm.Location) ‘获取该文件的基本代码格式的位置

        Console.WriteLine(asm.CodeBase) ‘获取最初指定的程序集的位置,一般来说和Location方法很相似

        Dim mo As [Module] 遍历模块

        For Each mo In asm.GetModules

            Console.WriteLine(mo.FullyQualifiedName)

        Next

        Dim ty As Type

        For Each ty In asm.GetTypes ‘遍历所有类型的信息

            Console.WriteLine(ty.FullName)

        Next

        ‘动态加载一个实例

        Dim o As Object = asm.CreateInstance("reflection_newtest.person")

        Console.WriteLine("********************")

   Console.WriteLine(o.GetType.FullName)

 

 

 

 说明: 这里的使用都比较简单,请继续往下看!

3.建立测试的过程

'获取遍历的类型,这里使用了系统类库文件mscorlib.dll

    Private Sub testtypeenumeration()

        Dim asm As [Assembly] = Reflection.Assembly.Load("mscorlib")

        Dim t As Type

        For Each t In asm.GetExportedTypes 对于当前的文件的测试

            If t.IsClass Then 如果是类

                Console.WriteLine(t.Name & "(class)")

            ElseIf t.IsEnum Then ‘如果是枚举

            ElseIf t.IsEnum Then ‘如果是枚举

            ElseIf t.IsEnum Then ‘如果是枚举

                Console.WriteLine(t.Name & "(enum)")

           ElseIf t.IsValueType Then ‘如果是值类型

           ElseIf t.IsValueType Then ‘如果是值类型

           ElseIf t.IsValueType Then ‘如果是值类型

                Console.WriteLine(t.Name & "(structure)")

             ElseIf t.IsInterface Then ‘如果是接口

             ElseIf t.IsInterface Then ‘如果是接口

             ElseIf t.IsInterface Then ‘如果是接口

                Console.WriteLine(Name & "(interface)")

            Else ‘其他

                '没做处理

            End If

        Next

    End Sub

'获取某一类型的所有信息(这里以string为例)

‘从上面的loadtype.gettype可见,他们都是创建assembly的方式

    Private Sub testatypememberinfo1()

        Dim stringtype As Type = Type.GetType("System.String") '获取指定名称的系统类型,也可以使用type.gettype(string)

        Dim minfos() As MemberInfo ‘类型数组

        Dim mi As MemberInfo

        minfos = stringtype.GetMembers

        For Each mi In minfos

            Console.WriteLine(mi.Name)

        Next

        '获得公共的非共享的并且是继承的成员

        minfos = stringtype.GetMembers(BindingFlags.Public Or BindingFlags.Instance Or BindingFlags.DeclaredOnly)

为了便于看清楚输出,做了间隔

        Console.WriteLine("*********************")

        For Each mi In minfos

            Console.WriteLine(mi.Name)

        Next

‘同样的间隔设置

        Console.WriteLine("*********************")

        '获取所有方法

        For Each mi In stringtype.GetMethods

            Console.WriteLine(mi.Name)

        Next

    End Sub

    '使用特定的显示某一种类型的方法

    Private Sub testatypememberinfo()

        Dim stringtype As Type = Type.GetType("System.String") '获取指定名称的系统类型

‘对于特定类型的属性的遍历

        Dim pinfos() As PropertyInfo = stringtype.GetProperties

        Dim mi As MemberInfo

        For Each mi In pinfos

            Console.WriteLine(mi.Name)

        Next

    End Sub

    '使用findmember方法对类型的遍历1

    Private Sub testfindmember1()

        Dim stringtype As Type = Type.GetType("System.String")

‘对于findmembers方法来说,它的参数分别为要获得的类型(可用or组合),筛选条件(可用or组合),

委托函数,传递给委托函数的参数。

        Dim minfos() As MemberInfo = stringtype.FindMembers(MemberTypes.Method _

        Or MemberTypes.Property, BindingFlags.Instance Or BindingFlags.Public, _

        AddressOf filterbyname1, "C")

        Dim mi As MemberInfo

        For Each mi In minfos

            Console.WriteLine(mi.Name)

        Next

    End Sub

    '委托函数一:筛选那些是以C开头的公共的实例的方法和属性(这个函数一旦返回true,意味着是符合要求的)

    Private Function filterbyname1(ByVal m As MemberInfo, ByVal filtercriteria As Object) As Boolean

        '如果成员名称以筛选函数的第2个参数开始,则返回true

        If m.Name.StartsWith(filtercriteria.ToString) Then

            Return True

        End If

    End Function

    '使用findmember方法对类型的遍历2

    Private Sub testfindmember2()

        Dim returntype As Type = Type.GetType("System.Int32")

        Dim minfos() As MemberInfo = returntype.FindMembers(MemberTypes.Method Or MemberTypes.Property, _

 BindingFlags.Instance Or BindingFlags.Public, AddressOf filterbyname2, returntype)

        Dim mi As MemberInfo

        For Each mi In minfos

            Console.WriteLine(mi.Name)

        Next

    End Sub

    '委托函数二

    Private Function filterbyname2(ByVal m As MemberInfo, ByVal filtercriteria As Object) As Boolean

        If m.MemberType = MemberTypes.Property Then

            Dim pi As PropertyInfo = CType(m, PropertyInfo)

            Return (pi.PropertyType Is filtercriteria) '如果该属性的类型与第2个参数相同则返回true

        ElseIf m.MemberType = MemberTypes.Method Then

            Dim mi As MethodInfo = CType(m, MethodInfo)

            Return (mi.ReturnType Is filtercriteria) '如果该方法的返回类型与第2个参数相同则返回true

        End If

    End Function

    '关于重载函数的调用

    Private Sub testoverloadmemberinfo()

        Dim stringtype As Type = Type.GetType("System.String")

        '一个类型数组

        Dim argtypes() As Type = {Type.GetType("System.String"), Type.GetType("System.String")}

        Dim mi As MemberInfo = stringtype.GetMethod("Compare", argtypes)

        Console.WriteLine(mi.Name)

    End Sub

    '枚举参数类型

    Private Sub testcallingsyntax()

        Dim stringtype As Type = Type.GetType("System.String")

        Dim stringtype As Type = Type.GetType("System.String")

        Dim stringtype As Type = Type.GetType("System.String")

        Dim mi As MethodInfo = stringtype.GetMethod("Copy")

        Dim pinfos() As ParameterInfo = mi.GetParameters

        Dim i As Integer

        '列出参数和参数的类型,中间用/连接

        For i = 0 To pinfos.GetUpperBound(0)

            Console.WriteLine(pinfos(i).Name & "/" & pinfos(i).ParameterType.ToString)

        Next

     End Sub

     End Sub

     End Sub

    '使用反射创建实例并给属性赋值

    Private Sub testreadwriteproperties()

         Try

         Try

         Try

            Dim asm As [Assembly] = Reflection.Assembly.LoadFrom("G:\练习\reflection_newtest\bin\reflection_newtest.dll")

            Dim ty As Type = asm.GetType("reflection_newtest.person")

            Dim m As Object = Activator.CreateInstance(ty)

 

 

 

 

            Dim pi As PropertyInfo = ty.GetProperty("age")

            pi.SetValue(m, 5S, Nothing) '一定要指定赋值的类型,如是short类型,一定要加s

            Console.WriteLine(pi.GetValue(m, Nothing))

            Console.WriteLine(pi.GetValue(m, Nothing))

            Console.WriteLine(pi.GetValue(m, Nothing))

        Catch ex As Exception

            MessageBox.Show(ex.Message)

        End Try

    End Sub

    '测试字符串属性(且含参数)

    Private Sub testreadwritepropertytieswithargs()

        Try

            Dim asm As [Assembly] = Reflection.Assembly.LoadFrom("G:\练习\reflection_newtest\bin\reflection_newtest.dll")

            Dim ty As Type = asm.GetType("reflection_newtest.person")

            Dim m As Object = Activator.CreateInstance(ty)

            Dim pi As PropertyInfo = ty.GetProperty("emailaddress")

            Dim params() As Object = {1S} '注意参数类型的严格匹配

            pi.SetValue(m, "321 north street", params)

           Console.WriteLine(pi.GetValue(m, params))

           Console.WriteLine(pi.GetValue(m, params))

           Console.WriteLine(pi.GetValue(m, params))

        Catch ex As Exception

            MessageBox.Show(ex.Message)

        End Try

    End Sub

    '使用invoke方法测试过程

    Private Sub testinvokemethod()

        Dim asm As [Assembly] = Reflection.Assembly.LoadFrom("G:\练习\reflection_newtest\bin\reflection_newtest.dll")

        Dim ty As Type = asm.GetType("reflection_newtest.person")

        Dim m As Object = Activator.CreateInstance(ty)

        Dim mi As MethodInfo = ty.GetMethod("sendemail")

        '定义过程的参数数组

        Dim params(mi.GetParameters.Length - 1) As Object

        Try

            params(0) = "this is message"

            params(1) = 3

            '触发过程

            mi.Invoke(m, params)

         Catch ex As Exception

         Catch ex As Exception

         Catch ex As Exception

            MessageBox.Show(ex.Message)

        End Try

    End Sub

    '使用invokemember方法测试过程

    Private Sub testinvokemember()

        Dim asm As [Assembly] = Reflection.Assembly.LoadFrom("G:\练习\reflection_newtest\bin\reflection_newtest.dll")

        Dim ty As Type = asm.GetType("reflection_newtest.person")

        Dim m As Object = Activator.CreateInstance(ty)

        Dim args() As Object = {"francesco"}

        Try

            '设置firstname字段值

            ty.InvokeMember("firstname", BindingFlags.SetField, Nothing, m, args)

            '读取firstname字段值,这个时候不用最后一个参数

            Dim value As Object = ty.InvokeMember("firstname", BindingFlags.GetField, Nothing, m, Nothing)

            Console.WriteLine(value.ToString)

            Dim args2() As Object = {35S} '注意这里的数组元素的类型一定要严格匹配short类型,

            '设置属性值,参数意味着是属性的参数

            ty.InvokeMember("age", BindingFlags.SetProperty, Nothing, m, args2)

            '读取属性值

            Dim value1 As Object = ty.InvokeMember("age", BindingFlags.GetProperty, Nothing, m, Nothing)

            Console.WriteLine(value1.ToString)

            Dim args3() As Object = {"this is a message", 2}

            '触发过程

            ty.InvokeMember("sendemail", BindingFlags.InvokeMethod, Nothing, m, args3)

         Catch ex As Exception

         Catch ex As Exception

         Catch ex As Exception

            MessageBox.Show(ex.Message)

        End Try

End Sub

///////////////////////////////////////////////////////////

    '动态地创建对象(使用默认地构造函数)

    Private Sub testobjectcreation1()

        Dim asm As [Assembly] = Reflection.Assembly.LoadFrom("G:\练习\reflection_newtest\bin\reflection_newtest.dll")

        Dim ty As Type = asm.GetType("reflection_newtest.person")

        Try

            Dim m As Object = Activator.CreateInstance(ty)

            Console.WriteLine("A {0} object has been created ", m.GetType.Name)

        Catch ex As Exception

            MessageBox.Show(ex.Message)

        End Try

    End Sub

    '使用带参数的方法(使用带参数的构造函数)

    Private Sub testobjectcreation2()

        Dim asm As [Assembly] = Reflection.Assembly.LoadFrom("G:\练习\reflection_newtest\bin\reflection_newtest.dll")

        Dim ty As Type = asm.GetType("reflection_newtest.person")

        Dim params() As Object = {"Joe", "Doe"}

        Try

            Dim o As Object = System.Activator.CreateInstance(ty, params)

            Console.WriteLine(o.GetType.Name)

        Catch ex As Exception

            MessageBox.Show(ex.Message)

        End Try

    End Sub

    '使用调用构造函数的方法来创建对象(实例)这个方法相对来说比较烦琐和麻烦。

    Private Sub testobjectcreation3()

        Dim asm As [Assembly] = Reflection.Assembly.LoadFrom("G:\练习\reflection_newtest\bin\reflection_newtest.dll")

        Dim ty As Type = asm.GetType("reflection_newtest.person")

        Dim types() As Type = {GetType(System.String), GetType(String)}

        Dim ci As ConstructorInfo = ty.GetConstructor(types) '获得这个有两个字符串参数的构造函数的信息

        Dim params() As Object = {"Joe", "Doe"} '用来初始化的数组

        Dim o As Object = ci.Invoke(params) '执行这个构造函数

        Console.WriteLine(o.GetType.Name)

End Sub

4. button2click事件中写:(该操作就是验证所有的测试过程,为了分辨出是哪个过程的结果,把其他的都暂时注释掉了。你可以根据需要来消除注释。)

'testtypeenumeration()

        'testatypememberinfo1()

        'testatypememberinfo2()

        'testfindmember1()

        'testfindmember2()

        testoverloadmemberinfo()

        'testcallingsyntax()

        'testreadwriteproperties()

        'testreadwritepropertytieswithargs()

        'testinvokemethod()

        'testinvokemember()

        'testobjectcreation1()

        'testobjectcreation2()

        'testobjectcreation3()

 

 

 

 说明:这里不多做过多地解释,代码中有比较完整的注释。如果有什么疏漏和错误,请指出!谢谢!

相关名词的简单说明:

反射(Reflection):.Net中获取运行时类型信息的方式

程序集(Assembly):编译后的.dllexe文件。可以获得正在运行的装配件信息,也可以动态的加载装配件,以及在装配件中查找类型信息,并创建该类型的实例。

类型(type):这里的类型区分于值类型与引用类型中的类型,它包括类,枚举,值类型,接口等。