VB.net学习笔记(十四) 反射、多态

来源:互联网 发布:纬创软件上海分公司 编辑:程序博客网 时间:2024/04/29 11:05


反射如同远程控制一样,进入对方电脑,返回对方电脑的相关资料。

所以:

第一:要对方支持(或者允许)进入(反射是内置于.Net Framwork中的一种技术)

第二:要有一定的方式进入(System.Reflection来获取另一个程序集或类)


简单地说:用反射来取得另一程序集中的相关信息(比如类、字段、属性、方法等)


反射又与多态有联系。下面逐步看看情况。




一、后期绑定实现多态性

 

        多态性:两个类在具有不同的实现代码的同时,拥有一组相同的方法、属性、事件。

                       这样可编写通用接口调用程序(而不用关心它是A类还是B类)


        在多态行为上,后期绑定是以降低性能和编程的使得性为代码,来实现纯多态性。

        

        新建立项目OOExample,添加类Encapsulation如下:

Imports System.MathPublic Class Encapsulation    Private mX As Single    Private mY As Single    Public Function DistanceTo(ByVal x As Single, ByVal y As Single) As Single        Return CSng(Sqrt((x - mX) ^ 2 + (y - mY) ^ 2))    End Function    Public Property CurrentX() As Single        Get            Return mX        End Get        Set(ByVal value As Single)            mX = value        End Set    End Property    Public Property CurrentY() As Single        Get            Return mY        End Get        Set(ByVal value As Single)            mY = value        End Set    End PropertyEnd Class

           窗体添加按钮,并添加单击代码:

Public Class Form1    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click        Dim obj As New Encapsulation        MsgBox(obj.DistanceTo(10, 10))    End SubEnd Class
         这里obj是强类型,即确切的一个具体类型,编译器在编译前就能确定它,所以又叫“前期绑定”

          下面用后期绑定:

           后期绑定:编译前没法确定类型(下例中类型object),需要在运行时才能确定类型(New Encaplsulation),这种称后期绑定。 改变窗体代码如下:

Public Class Form1    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click        Dim obj As Object = New Encapsulation        MsgBox(obj.DistanceTo(10, 10))    End SubEnd Class
         注意:如果Option Strict On将严格检查类型,它不允许后期绑定。所以在之前应关闭它,这样才允许后期绑定。

        

          后期绑定是在后台动态地确定对象的实际类型,并调用适当的方法。

          这时使用对象,IDE及编译器无法确定调用的方法是否正确(如无法确定上面obj是否有DistanceTo方法)。

          只能根据人为判断它有此成员(此时智能提示IntelliSense将失效)

          而且:后期绑定有严重的性能损失(每个方法是否存在都在运行时才能确定,将花费时间)

                      另外通过后期绑定的调用不如调用编译时已知的方法(前期绑定)效率高。



         将上面窗体代码分出通用方法,再来调用:

Public Class Form1    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click        Dim obj As New Encapsulation        ShowDistance(obj)    End Sub    Private Sub ShowDistance(ByVal obj As Object)        MsgBox(obj.DistanceTo(10, 10))    End SubEnd Class
       同样方法中用了object类型参数,也是后期绑定,如果传入时不匹配会出错。

        

         

       下面看后期绑定的多态性:

        添加新类Poly到上面项目中:

Public Class Poly    Public Function DistanceTo(ByVal x As Single, ByVal y As Single) As Single        Return x + y    End FunctionEnd Class
       注意:它同Encapsulation类一样也有方法DistanceTo,方法签名一样。

       改变窗体中按键单击代码,同样可以调用通过方法ShowDistance:

Public Class Form1    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click        Dim obj As New Poly        ShowDistance(obj)    End Sub    Private Sub ShowDistance(ByVal obj As Object)        MsgBox(obj.DistanceTo(10, 10))    End SubEnd Class

          可以看到,尽管传递给ShowDistance方法的对象也许是Poly,也许是Encapsulation类型,代码同样正常运行。

          即前面所说,不同对象调用通过方法,这样实现了后期绑定的多态性。








二、多接口实现多态性

 

       后期绑定比较灵活、简单,但费资源,且设计时不允许IDE和编译器进行类型检查,智能感应失效,无法检查输入错误。


       使用多接口,IDE和编译器可以在输入和编译时检查代码,智能感应可以使用。同时类型确认,代码执行速度更快。

       简单地说,多接口是一种强类型,属前期绑定。


        下面为上面项目添加多接口:

         添加模块,在其内新建一接口IShared:

Public Interface IShared    Function CalculateDistance(ByVal x As Single, ByVal y As Single) As SingleEnd Interface

         完善Encapsulation类和Poly类中的IShared接口:

Imports System.MathPublic Class Encapsulation    Implements IShared    Private mX As Single    Private mY As Single    Public Function DistanceTo(ByVal x As Single, ByVal y As Single) As Single Implements IShared.CalculateDistance        Return CSng(Sqrt((x - mX) ^ 2 + (y - mY) ^ 2))    End Function    Public Property CurrentX() As Single        Get            Return mX        End Get        Set(ByVal value As Single)            mX = value        End Set    End Property    Public Property CurrentY() As Single        Get            Return mY        End Get        Set(ByVal value As Single)            mY = value        End Set    End PropertyEnd ClassPublic Class Poly    Implements IShared    Public Function DistanceTo(ByVal x As Single, ByVal y As Single) As Single Implements IShared.CalculateDistance        Return x + y    End FunctionEnd Class


          窗体中再添加一个方法ShowDistance,注意它的类型是IShared,将与同名的Object参数重载。

          单击事件也改变:

Public Class Form1    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click        Dim obj As New Poly        Dim obj1 As IShared = obj        ShowDistance(obj)        ShowDistance(obj1)    End Sub    Private Sub ShowDistance(ByVal obj As Object)        MsgBox(obj.DistanceTo(10, 10))    End Sub    Private Sub ShowDistance(ByVal obj As IShared)        MsgBox(obj.CalculateDistance(10, 10))    End SubEnd Class
         两个都会调用最后一个,因为它“最匹配”。(注释后一个,程序运行也正常)

        可以看到:

        多接口,一样实现了多态,只要把通用方法(上面最后一个)写出,任意对象只要接口相同,就可以使用。

        同时也说明,不光是继承来多态,不同对象也可以多态!








三、反射实现多态性


         .Net中的反射使用入门

          http://blog.csdn.net/timmy3310/article/details/12615


        .NET中反射机制的使用与分析
         http://www.cnblogs.com/focusonnet/archive/2009/04/17/1438013.html



        反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。

        这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp

        和面向对象方面取得了成绩。其中LEAD/LEAD++ 、OpenC++ 、MetaXa和OpenJava等就是基于反射机制的语言。

        最近,反射机制也被应用到了视窗系统、操作系统和文件系统中。



        反射本身并不是一个新概念,它可能会使我们联想到光学中的反射概念,尽管计算机科学赋予了反射概念新的含义,

       但是,从现象上来说,它们确实有某些相通之处,这些有助于我们的理解。


        在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己

        行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行

        为的状态和相关的语义。


         可以看出,同一般的反射概念相比,计算机科学领域的反射不单单指反射本身,还包括对反射结果所采取的措施。所有采用

        反射机制的系统(即反射系统)都希望使系统的实现更开放。可以说,实现了反射机制的系统都具有开放性,但具有开放性

         的系统并不一定采用了反射机制,开放性是反射系统的必要条件。


        一般来说,反射系统除了满足开放性条件外还必须满足原因连接(Causally-connected)。所谓原因连接是指对反射系统自

        描述的改变能够立即反映到系统底层的实际状态和行为上的情况,反之亦然。开放性和原因连接是反射系统的两大基本要素。


         



            -----------------------------------------------------------------------------------------------------------------------------

            

             后期绑定速度较慢且难于调试,多接口限制较多,不够灵活。

            反射可以克服这些不足,反射是内置于.Net Framework中的一种技术,允许通过编写代码来查询.net程序集

            以动态地确定其包含的类和数据类型。(运行时才创建的实例都是动态)

            使用反射将该程序加载到进程中,并创建这些类的实例,调用它们的方法等。


            在使用后期绑定中,VB.net使用System.Reflection名称空间,该名称空间可用于浏览程序集或类的信息,以了解这些类,亦可手动使用反射,与其对象交互可获得更大的灵活性。


             下面在原项目基础上再添加一项目,OOExample项目利用反射去查看另一项目Objects。

              文件->添加->新项目,创建类库,名为Objects,在其内添加类External:

Public Class External    Public Function DistanceTo(ByVal x As Single, ByVal y As Single) As Single        Return x * y    End FunctionEnd Class

            注意:创建完后,一定要用 生成->生成Objects,这样才会生成一个Objects.dll。为下步作准备。

                         下面每个项目中都应检查调试前是否生成对应文件。



            主窗体中引用反射,并添加如下代码:

Option Strict OffImports System.Reflection '反射名字空间Public Class Form1    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click        Dim obj As Object        Dim dll As Assembly 'Reflection.Assembly类型,存储对Objects程序集的引用(下面动态加载)        dll = Assembly.LoadFrom("..\..\..\Objects\bin\Debug\Objects.dll") '动态加载        obj = dll.CreateInstance("Objects.External") '创建该程序集中External类的对象        MsgBox(obj.DistanceTo(10, 10))    End Sub    Private Sub ShowDistance(ByVal obj As Object)        MsgBox(obj.DistanceTo(10, 10))    End Sub    Private Sub ShowDistance(ByVal obj As IShared)        MsgBox(obj.CalculateDistance(10, 10))    End SubEnd Class

           利用Assembly.LoadFrom方法动态加载Objects这个外部程序集。反射库会从磁盘中加载程序集,一旦该程序庥加载到进行中,

            就可以使用dll变量来和它交互,包括对它进行查询,以获取其包含的类的列表,或创建这些类的实例。


          注意:亦可用AssemblyLoad方法,该方法通过扫描应用程序的exe文件(和全局程序集缓存)所在的目录,寻找包含Object程序集

                       的Exe或Dll,找到该程序集后,就把它加载到内在,以供使用。


                      

            


           此例关键在于定义了obj为Object类型,最后使用obj.DistanceTo,不同的程序集反射后,实例化成不同的对象,只要它们含有DistanceTo成员

           这样就可以调用这个通用方法,达到了多态的目的。













四、反射与多接口实现多态

               

            上面反射、多接口分别实现了各自的多态,下面,将结合这两个实现多态。


            在主程序、外部程序(集)建立通用接口(Interface),然后在运行时用反射动态加载外部程序集。


            继续上面的解决方案,添加相关操作,最终形成的解决方案如下(共3个项目)

              

             详细操作:文件->添加->新项目,添加新类库,名为Interfaces,在OOExample项目中,按住shift,拖动Interfaces.vb到项目Interfaces中,这样原OOExample中的接口IShared就移动到Interfaces项目中。

                                  在上图中右击OOExample(项目),选择添加引用,在下图中选中Interfaces。(意思是OOExample将引用Interfaces中的接口,因为本身的Ishared已经移至了Interfaces项目中了)

                                  同理对Objects添加一样的引用。



             在Objects项目中,添加引用和接口如下:

Imports InterfacesPublic Class External    Implements IShared    Public Function DistanceTo(ByVal x As Single, ByVal y As Single) As Single Implements IShared.CalculateDistance        Return x * y    End FunctionEnd Class


              在OOExample项目Poly类,改成如下代码:

Imports InterfacesPublic Class Poly    Implements IShared    Public Function DistanceTo(ByVal x As Single, ByVal y As Single) As Single Implements IShared.CalculateDistance        Return x + y    End FunctionEnd Class


           这样OOExample和Objects都完成了对另一个项目Interfaces(接口)的引用。示意图:

           

  


         这样主程序OOExample和外部程序Objects就可以使用同一个数据类型(Interfaces),然后用反射到外部程序中,实例化后转为同一类型(Interfaces)

           从而达到多态的效果。




            主程序代码如下:

Imports InterfacesImports System.ReflectionPublic Class Form1    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click        Dim obj As Object        Dim dll As Assembly        dll = Assembly.LoadFrom("..\..\..\Objects\bin\Debug\Objects.dll")        obj = CType(dll.CreateInstance("Objects.External"), IShared)        ShowDistance(obj)    End Sub    Private Sub ShowDistance(ByVal obj As Object)        MsgBox(obj.DistanceTo(10, 10))    End Sub    Private Sub ShowDistance(ByVal obj As IShared)        MsgBox(obj.CalculateDistance(10, 10))    End Sub    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load        Me.CustomerBindingSource.DataSource = New Customer    End SubEnd Class

         上面动态创建对象后,转为Ishared类型,通过ShowDistance实现。

          注意:上面每个项目应分别进行生成->生成XXX一次,再进行运行。



          多接口与反射的结合,使得最后调用方法ShowDistance的代码都是强类型(Ishared),提供了许多的方便和编码技术(智能感应生效),

          并且DLL和对象本身是动态加载,给应用程序提供了很大的灵活性。










五、继承实现多态


        子类对象总可以看作是父类的数据类型。

         继承可以实现多态,注意的是不用继承也可以实现多态(如多接口)。


          为了说明继承中的多态,添加一个基类Parent,它是Encapsulation类和Poly类的父类,它是一个虚拟基类:

Public MustInherit Class Parent    Public MustOverride Function DistanceTo(ByVal x As Single, ByVal y As Single) As SingleEnd Class

          对应的子类:Encapsulation类和Poly类也进行相应的修改:

Public Class Encapsulation    Inherits Parent    Implements IShared    Private mX As Single    Private mY As Single    Public Overrides Function DistanceTo(ByVal x As Single, ByVal y As Single) As Single Implements IShared.CalculateDistance        Return CSng(Sqrt((x - mX) ^ 2 + (y - mY) ^ 2))    End Function    '....End ClassImports InterfacesPublic Class Poly    Inherits Parent    Implements IShared    Public Overrides Function DistanceTo(ByVal x As Single, ByVal y As Single) As Single Implements IShared.CalculateDistance        Return x + y    End FunctionEnd Class

       注意:必须重写基类Encapsulation的DistanceTo方法。



        主程序中修改如下代码:

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click        ShowDistance(New Poly)        ShowDistance(New Encapsulation)    End Sub    Private Sub ShowDistance(ByVal obj As Parent)        MsgBox(obj.DistanceTo(10, 10))    End Sub

         这样只要传入ShowDistance方法的参数是Parent的子类,均可以使用这个通用方法,达到多态目的。









六、总结


        多态可以通过许多技术达到,下面是各技术优缺点:


        后期绑定:优点——灵活、具有纯多态性,                              

                            缺点 —— 迟钝、难于调试,没有智能感应

                            适用——用于调用任何对象中的任何方法,无须考虑数据类型或接口。

 

         多接口:   优点——快、容易调试,有智能感应。                  

                            缺点——不能完全动态,不灵活,需要类的创建者实现统一的接口

                           适用——当创建与多个明确定义的方法(这些方法可以组合成一个正式接口)交互的代码时使用


          反射与后期绑定:优点——灵活、纯多态性,可动态加载磁盘的任意程序集

                                          缺点——迟钝、难于调试,没有智能感应

                                          适用——如果在设计时不知道将要用哪到哪一个程序集,就使用该技术调用任何对象中的任何方法


            反射与多接口:优点——快、易调试,有智能感应,可以动态地加载磁盘中的任意程序集

                                        缺点——不能完全动态,不灵活,需要类的创建者实现统一的接口

                                        适用——当创建与明确定义的方法(这些方法可以组合为一个正式接口)交互的代码时,如果

                                                         不知道将要用到哪一个程序集,就使用该技术


             继承:优点——快、易调试,有智能感应,继承蕨类的行为

                         缺点——不能完全动态,不灵活,需要类的创建者继承公共的基类

                        适用——当有继承关系时使用,通过继承可以实现多态是因为继承有意义,而不是因为只想获取多态性。(即继承才是目的,多态不是目的)


源代码存盘:http://download.csdn.net/detail/dzweather/5979279





原创粉丝点击