通过例子,浅谈反射(Reflection)的应用 - .NET专区 - 新云网络

来源:百度文库 编辑:神马文学网 时间:2024/04/28 11:52:38
通过例子,浅谈反射(Reflection)的应用减小字体 增大字体 作者:佚名 来源:本站整理 发布时间:2005-6-15 10:08:50说明:应该说这篇短文根本算不上什么深入的分析性的文章,所以在标题前加上了“浅谈”二字,希望对于一般的读者来说,可以给你一个相对直观些的对反射的认识。 --2005/05/23 于东莞在这里对反射以及反射的概念在最后给出简要的解释。一.用来测试的程序集文件的建立。首先你需要建立一个类库文件(编译后扩展名为.dll),名字假设为:reflection_newtest 系统会默认地新建一个类文件class1,把它该成我们用来测试的类person 具体代码如下:(类的代码比较简单,这里不做解释,如有不明之处,请查看类的相关文档.) Public Class person Public firstname As String Public lastname As String Dim m_age As Short Dim m_emailaddress(4) As String Public Sub New() MyBase.new() End Sub Public Sub New(ByVal firstname As String, ByVal lastname As String) Me.firstname = firstname Me.lastname = lastname End Sub Public Property age() As Short Get Return m_age End Get Set(ByVal Value As Short) m_age = Value End Set End Property Public Property emailaddress(ByVal index As Short) As String Get Return m_emailaddress(index) End Get Set(ByVal Value As String) m_emailaddress(index) = Value End Set End Property Sub sendemail(ByVal msg As String, Optional ByVal priorty As Integer = 1) Console.WriteLine("message to " & firstname & " " & lastname) Console.WriteLine("priority " & priorty.ToString) Console.WriteLine(msg) End Sub End Class 二.测试验证的程序 建立一个winform的程序,命名假设为:testreflection 从工具栏里拖两个按钮,命名为button1,button2. 1.在程序的最上面加入引用: Imports System Imports System.Reflection Imports System.Type 2.在button1的click事件里写: Dim asm As [Assembly] ‘由于assembly是关键字,所以要加[] asm = Reflection.Assembly.LoadFrom("G:\练习\reflection_newtest\bin\reflection_newtest.dll") ‘这里假设上面的reflection_newtest文件的位置在G:\练习 的文件夹。 Console.WriteLine(asm.FullName) ‘输出完全限定名 Console.WriteLine(asm.Location) ‘获取该文件的基本代码格式的位置 Console.WriteLine(asm.CodeBase) ‘获取最初指定的程序集的位置,一般来说和Location方法很相似 Dim mo As [Module] ‘遍历模块 For Each mo In asm.GetModules Console.WriteLine(mo.FullyQualifiedName) Next Dim ty As Type For Each ty In asm.GetTypes ‘遍历所有类型的信息 Console.WriteLine(ty.FullName) Next ‘动态加载一个实例 Dim o As Object = asm.CreateInstance("reflection_newtest.person") Console.WriteLine("********************") Console.WriteLine(o.GetType.FullName) 说明: 这里的使用都比较简单,请继续往下看! 3.建立测试的过程 '获取遍历的类型,这里使用了系统类库文件mscorlib.dll Private Sub testtypeenumeration() Dim asm As [Assembly] = Reflection.Assembly.Load("mscorlib") Dim t As Type For Each t In asm.GetExportedTypes ‘对于当前的文件的测试 If t.IsClass Then ‘如果是类 Console.WriteLine(t.Name & "(class)") ElseIf t.IsEnum Then ‘如果是枚举 Console.WriteLine(t.Name & "(enum)") ElseIf t.IsValueType Then ‘如果是值类型 Console.WriteLine(t.Name & "(structure)") ElseIf t.IsInterface Then ‘如果是接口 Console.WriteLine(Name & "(interface)") Else ‘其他 '没做处理 End If Next End Sub '获取某一类型的所有信息(这里以string为例) ‘从上面的load与type.gettype可见,他们都是创建assembly的方式 Private Sub testatypememberinfo1() Dim stringtype As Type = Type.GetType("System.String") '获取指定名称的系统类型,也可以使用type.gettype(string) Dim minfos() As MemberInfo ‘类型数组 Dim mi As MemberInfo minfos = stringtype.GetMembers For Each mi In minfos Console.WriteLine(mi.Name) Next '获得公共的非共享的并且是继承的成员 minfos = stringtype.GetMembers(BindingFlags.Public Or BindingFlags.Instance Or BindingFlags.DeclaredOnly) ‘为了便于看清楚输出,做了间隔 Console.WriteLine("*********************") For Each mi In minfos Console.WriteLine(mi.Name) Next ‘同样的间隔设置 Console.WriteLine("*********************") '获取所有方法 For Each mi In stringtype.GetMethods Console.WriteLine(mi.Name) Next End Sub '使用特定的显示某一种类型的方法 Private Sub testatypememberinfo() Dim stringtype As Type = Type.GetType("System.String") '获取指定名称的系统类型 ‘对于特定类型的属性的遍历 Dim pinfos() As PropertyInfo = stringtype.GetProperties Dim mi As MemberInfo For Each mi In pinfos Console.WriteLine(mi.Name) Next End Sub '使用findmember方法对类型的遍历1 Private Sub testfindmember1() Dim stringtype As Type = Type.GetType("System.String") ‘对于findmembers方法来说,它的参数分别为要获得的类型(可用or组合),筛选条件(可用or组合), 委托函数,传递给委托函数的参数。 Dim minfos() As MemberInfo = stringtype.FindMembers(MemberTypes.Method _ Or MemberTypes.Property, BindingFlags.Instance Or BindingFlags.Public, _ AddressOf filterbyname1, "C") Dim mi As MemberInfo For Each mi In minfos Console.WriteLine(mi.Name) Next End Sub '委托函数一:筛选那些是以C开头的公共的实例的方法和属性(这个函数一旦返回true,意味着是符合要求的) Private Function filterbyname1(ByVal m As MemberInfo, ByVal filtercriteria As Object) As Boolean '如果成员名称以筛选函数的第2个参数开始,则返回true If m.Name.StartsWith(filtercriteria.ToString) Then Return True End If End Function '使用findmember方法对类型的遍历2 Private Sub testfindmember2() Dim returntype As Type = Type.GetType("System.Int32") Dim minfos() As MemberInfo = returntype.FindMembers(MemberTypes.Method Or MemberTypes.Property, _ BindingFlags.Instance Or BindingFlags.Public, AddressOf filterbyname2, returntype) Dim mi As MemberInfo For Each mi In minfos Console.WriteLine(mi.Name) Next End Sub '委托函数二 Private Function filterbyname2(ByVal m As MemberInfo, ByVal filtercriteria As Object) As Boolean If m.MemberType = MemberTypes.Property Then Dim pi As PropertyInfo = CType(m, PropertyInfo) Return (pi.PropertyType Is filtercriteria) '如果该属性的类型与第2个参数相同则返回true ElseIf m.MemberType = MemberTypes.Method Then Dim mi As MethodInfo = CType(m, MethodInfo) Return (mi.ReturnType Is filtercriteria) '如果该方法的返回类型与第2个参数相同则返回true End If End Function '关于重载函数的调用 Private Sub testoverloadmemberinfo() Dim stringtype As Type = Type.GetType("System.String") '一个类型数组 Dim argtypes() As Type = {Type.GetType("System.String"), Type.GetType("System.String")} Dim mi As MemberInfo = stringtype.GetMethod("Compare", argtypes) Console.WriteLine(mi.Name) End Sub '枚举参数类型 Private Sub testcallingsyntax() Dim stringtype As Type = Type.GetType("System.String") Dim mi As MethodInfo = stringtype.GetMethod("Copy") Dim pinfos() As ParameterInfo = mi.GetParameters Dim i As Integer '列出参数和参数的类型,中间用/连接 For i = 0 To pinfos.GetUpperBound(0) Console.WriteLine(pinfos(i).Name & "/" & pinfos(i).ParameterType.ToString) Next End Sub '使用反射创建实例并给属性赋值 Private Sub testreadwriteproperties() Try Dim asm As [Assembly] = Reflection.Assembly.LoadFrom("G:\练习\reflection_newtest\bin\reflection_newtest.dll") Dim ty As Type = asm.GetType("reflection_newtest.person") Dim m As Object = Activator.CreateInstance(ty) Dim pi As PropertyInfo = ty.GetProperty("age") pi.SetValue(m, 5S, Nothing) '一定要指定赋值的类型,如是short类型,一定要加s Console.WriteLine(pi.GetValue(m, Nothing)) Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub '测试字符串属性(且含参数) Private Sub testreadwritepropertytieswithargs() Try Dim asm As [Assembly] = Reflection.Assembly.LoadFrom("G:\练习\reflection_newtest\bin\reflection_newtest.dll") Dim ty As Type = asm.GetType("reflection_newtest.person") Dim m As Object = Activator.CreateInstance(ty) Dim pi As PropertyInfo = ty.GetProperty("emailaddress") Dim params() As Object = {1S} '注意参数类型的严格匹配 pi.SetValue(m, " 321 north street", params) 321 north street", params) Console.WriteLine(pi.GetValue(m, params)) Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub '使用invoke方法测试过程 Private Sub testinvokemethod() Dim asm As [Assembly] = Reflection.Assembly.LoadFrom("G:\练习\reflection_newtest\bin\reflection_newtest.dll") Dim ty As Type = asm.GetType("reflection_newtest.person") Dim m As Object = Activator.CreateInstance(ty) Dim mi As MethodInfo = ty.GetMethod("sendemail") '定义过程的参数数组 Dim params(mi.GetParameters.Length - 1) As Object Try params(0) = "this is message" params(1) = 3 '触发过程 mi.Invoke(m, params) Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub '使用invokemember方法测试过程 Private Sub testinvokemember() Dim asm As [Assembly] = Reflection.Assembly.LoadFrom("G:\练习\reflection_newtest\bin\reflection_newtest.dll") Dim ty As Type = asm.GetType("reflection_newtest.person") Dim m As Object = Activator.CreateInstance(ty) Dim args() As Object = {"francesco"} Try '设置firstname字段值 ty.InvokeMember("firstname", BindingFlags.SetField, Nothing, m, args) '读取firstname字段值,这个时候不用最后一个参数 Dim value As Object = ty.InvokeMember("firstname", BindingFlags.GetField, Nothing, m, Nothing) Console.WriteLine(value.ToString) Dim args2() As Object = {35S} '注意这里的数组元素的类型一定要严格匹配short类型, '设置属性值,参数意味着是属性的参数 ty.InvokeMember("age", BindingFlags.SetProperty, Nothing, m, args2) '读取属性值 Dim value1 As Object = ty.InvokeMember("age", BindingFlags.GetProperty, Nothing, m, Nothing) Console.WriteLine(value1.ToString) Dim args3() As Object = {"this is a message", 2} '触发过程 ty.InvokeMember("sendemail", BindingFlags.InvokeMethod, Nothing, m, args3) Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub ‘/////////////////////////////////////////////////////////// '动态地创建对象(使用默认地构造函数) Private Sub testobjectcreation1() Dim asm As [Assembly] = Reflection.Assembly.LoadFrom("G:\练习\reflection_newtest\bin\reflection_newtest.dll") Dim ty As Type = asm.GetType("reflection_newtest.person") Try Dim m As Object = Activator.CreateInstance(ty) Console.WriteLine("A {0} object has been created ", m.GetType.Name) Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub '使用带参数的方法(使用带参数的构造函数) Private Sub testobjectcreation2() Dim asm As [Assembly] = Reflection.Assembly.LoadFrom("G:\练习\reflection_newtest\bin\reflection_newtest.dll") Dim ty As Type = asm.GetType("reflection_newtest.person") Dim params() As Object = {"Joe", "Doe"} Try Dim o As Object = System.Activator.CreateInstance(ty, params) Console.WriteLine(o.GetType.Name) Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub '使用调用构造函数的方法来创建对象(实例)这个方法相对来说比较烦琐和麻烦。 Private Sub testobjectcreation3() Dim asm As [Assembly] = Reflection.Assembly.LoadFrom("G:\练习\reflection_newtest\bin\reflection_newtest.dll") Dim ty As Type = asm.GetType("reflection_newtest.person") Dim types() As Type = {GetType(System.String), GetType(String)} Dim ci As ConstructorInfo = ty.GetConstructor(types) '获得这个有两个字符串参数的构造函数的信息 Dim params() As Object = {"Joe", "Doe"} '用来初始化的数组 Dim o As Object = ci.Invoke(params) '执行这个构造函数 Console.WriteLine(o.GetType.Name) End Sub 4. button2的click事件中写:(该操作就是验证所有的测试过程,为了分辨出是哪个过程的结果,把其他的都暂时注释掉了。你可以根据需要来消除注释。) 'testtypeenumeration() 'testatypememberinfo1() 'testatypememberinfo2() 'testfindmember1() 'testfindmember2() testoverloadmemberinfo() 'testcallingsyntax() 'testreadwriteproperties() 'testreadwritepropertytieswithargs() 'testinvokemethod() 'testinvokemember() 'testobjectcreation1() 'testobjectcreation2() 'testobjectcreation3() 说明:这里不多做过多地解释,代码中有比较完整的注释。如果有什么疏漏和错误,请指出!谢谢! 相关名词的简单说明: 反射(Reflection):.Net中获取运行时类型信息的方式程序集(Assembly):编译后的.dll和exe文件。可以获得正在运行的装配件信息,也可以动态的加载装配件,以及在装配件中查找类型信息,并创建该类型的实例。类型(type):这里的类型区分于值类型与引用类型中的类型,它包括类,枚举,值类型,接口等。