反射如同远程控制一样,进入对方电脑,返回对方电脑的相关资料。
所以:
第一:要对方支持(或者允许)进入(反射是内置于.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两个都会调用最后一个,因为它“最匹配”。(注释后一个,程序运行也正常)
可以看到:
多接口,一样实现了多态,只要把通用方法(上面最后一个)写出,任意对象只要接口相同,就可以使用。
同时也说明,不光是继承来多态,不同对象也可以多态!
三、反射实现多态性
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("..\..\..\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 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("..\..\..\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 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
原文链接:https://www.f2er.com/vb/258601.html