很久以前就听说过反射 了,那时觉得这是个很高深的技术,其实也没什么,.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里的类列表或者其他模块,然后调用类的方法,你看,这个过程是不是运行时才有的,可是你也能在编码时做到了,你可以把药材全部找出来
值得注意的是,应用程序的隔离单位从最初的进程为单位,到现在以应用程序域为单位,减少了进程切换带来的开销同时又具备隔离的效果.
可以调用类的方法,或者设置类的变量值,可以根据类名来动态创建对象(当你在类中定义的SUB NEW是PRIVATE的,而你又非要创建它,那么就反射吧,当然,如果你的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") ‘通过类型来工作
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,成功
大家已经看到了,反射是如此的危险,他可以通过非法路径来执行你不希望看到的结果。
以上是反射的一般应用,我们试着在实际项目中使用它。下篇文章将作介绍。
有疑问的可以问问。呵呵!