反射的技术实践

来源:互联网 发布:淘宝店装修 编辑:程序博客网 时间:2024/05/18 07:36

很久以前就听说过反射 了,那时觉得这是个很高深的技术,其实也没什么,.net架构内建的技术,有兴趣的朋友可以进
System.Reflection命名空间里面看看。一直都想把一些技术的心得想下来,一来帮助初学者少走弯路,其实技术都是简单的,应用才是关键,二来我也想复习,三来嘛,希望交些朋友,我的qq 829098,欢迎同道中人加我。

大家都知道,正常的编码是这样的,我们定义好类,通过实例化类来取得对象,调用对象的方法完成我们的任务,可能由一组类来协作一个任务,我们把这些相关类放到一个命名空间里,生成为一个dll程序集,可以部署的是程序集,而不是类,

我们的系统在运行的时候将把dll(动态链接库)加载到当前进程的一个默认的应用程序域,application.currentdomain.load方法可以取得当前域的所有dll,也可以unload方法将dll从该域卸载掉,通过执行dll的方法来响应用户的操作,执行完后,就释放了这个dll.,这是运行时的行为,可以看出

,运行时依赖的是DLL,这对我们开发者而言,DLL是结束而不是开始,因为从编码到编译成功,得到PE文件,PE文件之间的关系就固定下来了,DLL就像你煲好的药,药材早就变质了,系统也就固定下来不可改了,无法再伸缩它

但是反射它改变了你的想法,你反过来看,你可以从当前进程的应用程序域取得DLL开始(application.currentdomain.load取出该进程的所有的DLL列表),取得DLL里的类列表或者其他模块,然后调用类的方法,你看,这个过程是不是运行时才有的,可是你也能在编码时做到了,你可以把药材全部找出来

值得注意的是,应用程序的隔离单位从最初的进程为单位,到现在以应用程序域为单位,减少了进程切换带来的开销同时又具备隔离的效果.

 
那么反射该怎么理解呢?简单的说,反射就是可以取得一个dll里面的所有类或者模块等等的列表,可以取得每个类或模块的所有公共和私有成员

可以调用类的方法,或者设置类的变量值,可以根据类名来动态创建对象(当你在类中定义的SUB NEWPRIVATE的,而你又非要创建它,那么就反射吧,当然,如果你的SUB NEW带了参数那就行不通,反正,它是个后门,它破坏了封装,但是有时候却非

要它不可, 假如有这么一个产品类,跟我一起看看,我相信你看了马上就明白了。

Public Class product

    Private mname As String

    Property name() As String

        Get

            Return mname

        End Get

        Set(ByVal value As String)

            mname = value

        End Set

    End Property

 

    Private mprice As Decimal = 200

    Property price() As Decimal

        Get

            Return mprice

        End Get

        Set(ByVal value As Decimal)

            mprice = value

        End Set

    End Property

 

    Private mid As Guid = Guid.NewGuid

    ReadOnly Property id() As Guid

        Get

            Return mid

        End Get

    End Property

 

    Public Sub buy(ByVal number As Integer)

        mprice *= number

    End Sub

 

End Class

‘假如这个BUY方法返回买了NUMBER件产品的价格

                 

’那么利用反射来取得产品类的所有方法       

          Dim t As Type = Type.GetType("WindowsApplication1.Priduct") ‘通过类型来工作

    

        Dim minfo As MemberInfo() = t.GetMembers()   ‘查看所有方法名知道有BUY这个方法,好,我们就可以调用它了

        For Each i As MemberInfo In minfo

            If i.Name.Equals("buy") Then

                Dim methond As MethodInfo = t.GetMethod("buy")

                Dim p() As Object = {5}

                MessageBox.Show(c.price.ToString)

                methond.Invoke(c, p)   ’调用BUY方法

dim c as product =Activator.CreateInstance(t)

                MessageBox.Show(c.price.ToString)       OK,值被改了,本来是200,现在是1000了,如果传的参数是负数

,呵呵。那就是负1000了,所以开发者一定要记得在方法里面做判断的,这是业务逻辑,不可不写!

            End If

         Next

 
‘取得私有字段也同样的道理

 Dim finfo As FieldInfo() = t.GetFields

        For Each f As FieldInfo In finfo

            Dim p() As Object = {2}

 

            If f.Name.Equals("要处理的字段名") Then

                MessageBox.Show(c.price.ToString)

                f.SetValue(c, p)

                MessageBox.Show(c.price.ToString)  ’可以看到价格被改了

            End If

 

        Next

我们知道有哪些字段了,找出我们关心的,比如price,我们将默认值200改成2的方法是这样的。

好吧,再来个杀伤力 更厉害的,先在刚才的产品类加个初始化类的方法

private sub new

end sub

假如我们的产品类的sub new是private的,那么刚才上面的代码在编写的时候编译器 就不让我们通过了 Dim c As New product (找不到NEW方法嘛),很好,用反射吧OK

  Dim t As Type = Type.GetType("WindowsApplication1.Priduct")  ’这里我试了几次才发现,参数要包括项目的命名空间和类名,也就是完整名称。之前把命名空间说成项目名,闹笑话了。呵呵。写出来还是好,有高人指正。

 
        Dim obj As product= Activator.CreateInstance(t,true) ’传类型进去即可取得新创建的对象了,注意那个true参数,因为一开始没传进去,结果搞了老半天才调试成功,参数2的意思是:nonPublic: 如果公共或非公共默认构造函数可以匹配,则为 true;如果只有公共默认构造函数可以匹配,则为 false。

        MessageBox.Show(obj.name)  ‘
OK,成功

大家已经看到了,反射是如此的危险,他可以通过非法路径来执行你不希望看到的结果。

 

以上是反射的一般应用,我们试着在实际项目中使用它。下篇文章将作介绍。

  有疑问的可以问问。呵呵!
另外在群友的提醒下改了两个地方的错误,1是我用反射的时候是完全靠类型工作的,我之前写了个创建实例的方法,这可不是晚期绑定,第2个错误是我在使用后门方法CreateInstanct时创建实例,此时如果类的构造器是私有的但带参数,则没法调用通过,在此感谢该群友 !

2。反射的项目实战,将枚举转换成列表的办法 
3。按位运算的项目实践,接上文的反射项目实践
原创粉丝点击