加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-17 08:08:50 所属栏目:百科 来源:网络整理
导读:反射如同远程控制一样,进入对方电脑,返回对方电脑的相关资料。 所以: 第一:要对方支持(或者允许)进入(反射是内置于.Net Framwork中的一种技术) 第二:要有一定的方式进入(System.Reflection来获取另一个程序集或类) 简单地说:用反射来取得另一程序


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

所以:

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

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


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


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




一、后期绑定实现多态性

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

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


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

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

Imports System.Math
Public 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 Property

End 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 Sub
End 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 Sub
End 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 Sub
End Class
同样方法中用了object类型参数,也是后期绑定,如果传入时不匹配会出错。

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

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

Public Class Poly
    Public Function DistanceTo(ByVal x As Single,ByVal y As Single) As Single
        Return x + y
    End Function
End 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 Sub
End Class

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

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








二、多接口实现多态性

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


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

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


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

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

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

完善Encapsulation类和Poly类中的IShared接口:
Imports System.Math
Public 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 Property
End Class



Public Class Poly
    Implements IShared
    Public Function DistanceTo(ByVal x As Single,ByVal y As Single) As Single Implements IShared.CalculateDistance
        Return x + y
    End Function
End 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 Sub
End 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 Function
End Class

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

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



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

Option Strict Off
Imports 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("......ObjectsbinDebugObjects.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 Sub
End 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 Interfaces
Public Class External
    Implements IShared
    Public Function DistanceTo(ByVal x As Single,ByVal y As Single) As Single Implements IShared.CalculateDistance
        Return x * y
    End Function
End Class


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

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


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


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

从而达到多态的效果。




主程序代码如下:

Imports Interfaces
Imports 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
        dll = Assembly.LoadFrom("......ObjectsbinDebugObjects.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 Form1_Load(sender As Object,e As EventArgs) Handles MyBase.Load
        Me.CustomerBindingSource.DataSource = New Customer
    End Sub
End 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 Single
End 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 Class



Imports Interfaces
Public 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 Function
End 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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读