首页 > 编程 > .NET > 正文

浅谈VB.NET文章系列之一 --通过例子,浅谈反射(Reflection)的应用

2024-07-10 13:00:30
字体:
来源:转载
供稿:网友
浅谈vb.net文章系列之一通过例子,浅谈反射(reflection)的应用说明:应该说这篇短文根本算不上什么深入的分析性的文章,所以在标题前加上了“浅谈”二字,希望对于一般的读者来说,可以给你一个相对直观些的对反射的认识。                                                             --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()

        mybase.new()

    end sub

  

    public sub new(byval firstname as string, byval lastname as string)

        me.firstname = firstname

        me.lastname = lastname

    end sub

  

    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.在button1的click事件里写:

  

  

        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 ‘如果是枚举

                console.writeline(t.name & "(enum)")

  

            elseif t.isvaluetype then ‘如果是值类型

                console.writeline(t.name & "(structure)")

  

            elseif t.isinterface then ‘如果是接口

                console.writeline(name & "(interface)")

            else ‘其他

                '没做处理

            end if

        next

    end sub

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

‘从上面的load与type.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 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

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

    private sub testreadwriteproperties()

  

        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))

        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) 321 north street", 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

            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

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

'testtypeenumeration()

        'testatypememberinfo1()

        'testatypememberinfo2()

        'testfindmember1()

        'testfindmember2()

        testoverloadmemberinfo()

        'testcallingsyntax()

        'testreadwriteproperties()

        'testreadwritepropertytieswithargs()

        'testinvokemethod()

        'testinvokemember()

        'testobjectcreation1()

        'testobjectcreation2()

        'testobjectcreation3()

  

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

相关名词的简单说明: 反射(reflection):.net中获取运行时类型信息的方式程序集(assembly):编译后的.dll和exe文件。可以获得正在运行的装配件信息,也可以动态的加载装配件,以及在装配件中查找类型信息,并创建该类型的实例。类型(type):这里的类型区分于值类型与引用类型中的类型,它包括类,枚举,值类型,接口等。菜鸟学堂:

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表