解析
反射技术在运行时可以获取程序集中每个类型的成员,包括字段、方法、属性、事件等,并进一步获取这些成员的详细信息。反射技术还可以动态载入外部程序集(私有程序集或共享程序集),获取程序集中类型的相关数据。有意思的是从外部动态载入的程序集还可通过晚期绑定,创建外部程序集中某类型的实例(对象),并且可以进一步调用其成员(如方法和属性)。在这个过程中,并不知道外部程序集的任何信息(甚至不知道该程序集是否存在)。 简而言之,反射技术以编程的方式获取程序集的元数据信息,通常情况下,只能通过ildasm.exe程序载入程序集或模块,才能读取其元数据。 NET的反射技术从程序集中获取各种细节类型元数据(如FieldInfo类描述了字段的细节)实例,并做进一步的操作,而这些细节类型大多数属于 System.Reflection命名空间。 说明:ildasm.exe是.Net Framework自带的程序,用于查看程序集的IL代码、元数据等信息。假设C盘是系统分区,则ildasm.exe程序通常位于C:\WINDOWS \Microsoft.NET\ Framework\v2.0.50727目录下。 System.Reflection命名空间包含了很多与反射有关的类型,通过这些类型可以获取指定类型的所有细节。本题要求获取指定类型中方法的完整信息,而System.Reflection命名空间下关于方法的类型为MethodInfo类型和ParameterInfo类型,所以只需要获取指定类型中方法的这2个类相关的对象即可。要达到这个目的,需要获取表示指定类型元数据的Type对象,Type对象即System.Type类的实例,该对象的成员可以返回System.Reflection命名空间下的类型,包括MethodInfo类型和ParameterInfo类型。在前面的示例中使用了对象的GetType方法获取类型名称,除此之外,还有多种获取Type对象的方法,如以下代码所示: +展开
-C#
//调用对象的GetType方法获取Type对象的引用
Type 对象引用变量 = 对象.GetType(); //调用Type类GetType静态方法的不同重载版本 Type 对象引用变量 = System.Type.GetType("类型的全饰名称"); Type 对象引用变量 = System.Type.GetType("类型的全饰名称", 是否抛出异常, 是否不区分大小写); Type 对象引用变量 = System.Type.GetType("类型的全饰名称, 类型所属程序集的友好名称"); //使用C#的typeof运算符 Type 对象引用变量 = typeof(类型名称); 以上代码,调用Type类的GetType()静态方法,其中第3个重载版本用于获取外部私有程序集类型的Type对象。当获取指定类型的Type对象后,就可以通过其成员返回MethodInfo类型和ParameterInfo类型,以达到获取方法完整信息的目的,如以下代码所示: +展开
-C#
using System;
using System.Reflection; MethodInfo[] 方法数组 = Type.GetType("类型的全饰名称", false, false); 使用foreach语句遍历方法数组的每个子项,即可访问类型中方法的所有信息; //在foreach语句中,调用方法数组子项的GetParameters方法,可返回ParameterInfo类型的参数数组 ParameterInfo参数数组 = 方法数组子项.GetParameters(); 使用foreach语句遍历参数数组的每个子项,即可访问方法中参数的所有信息; 以上代码使用了foreach语句,可访问方法中参数的所有信息。 注意:默认情况下,反射只能获取公共成员的信息,而访问非公共成员可能会带来安全危险。因此,访问非公共成员的代码需要带有适当标志的 ReflectionPermission。此外,某些任务(例如执行非托管代码和序列化对象)还需要SecurityPermission。 面试例题7:如何利用反射获取当前程序集指定类型的信息? 考点:反射技术获取类型信息的方法以及获取类型成员集合的方法。 出现频率:★★ 解答 获取指定类型的信息只需要获取该类型的Type对象,然后调用其成员即可。获取执行代码封装于ClassB类的静态方法Ref()中,用户输入不同的值,反射不同类型的详细信息。在目录下新建一个程序文件,并命名为ClassRef.cs,编写代码如代码7.7所示。 代码7.7 反射指定类型的信息:ClassRef.cs +展开
-C#
using System;
//导入相应的命名空间 using System.Reflection; class ClassRef { static void Main(string[] args) { while (true) { Console.Write("请输入所检测的类型名称:"); //接收用户输入值并赋值给input变量 string input = Console.ReadLine(); //如果用户输入"quit",则跳出循环 if (input == "quit") { break; } try { //调用Type类的静态方法GetType,并将Type对象引用返回给tp变量 Type tp = Type.GetType(input, false, false); //调用ClassB的Ref静态方法,并传递tp对象 ClassB.Ref(tp); } //捕获空对象引用异常 catch (NullReferenceException e) { //输出异常信息 Console.WriteLine("异常信息:{0}", e.Message); } //捕获一般异常 catch (Exception e) { //输出异常信息 Console.WriteLine("异常信息:{0}", e.Message); } } } } //定义2个接口类型IClassA和IClassB public interface IClassA { string MethodA(string s); } public interface IClassB { string Name { get; } } //定义ClassA,该类继承于接口类型IClassA和IClassB class ClassA : IClassA,IClassB { public string _name; public string Name { get { return _name; } } //定义internal权限的MethodA方法 public string MethodA(string s) { _name = s; return _name; } //定义public权限的MethodB方法 public ClassA(string s) { Console.WriteLine("所接收的参数是:{0}", s); } } class ClassB { string _name; //定义internal权限的MethodB方法 internal string MethodB(string s) { _name = s; return _name; } //定义静态方法Ref,接收1个Type类型的参数 public static void Ref(Type tp) { //输出Type对象的基本属性 string FullName = tp.FullName; Console.WriteLine("\n\t============={0}类型的信息=============", FullName); Console.WriteLine("{0}是泛型类型吗?->{1}", FullName, tp.IsGenericType); Console.WriteLine("{0}是接口类型吗?->{1}", FullName, tp.IsInterface); Console.WriteLine("{0}是类类型吗?->{1}",FullName,tp.IsClass); Console.WriteLine("{0}是COM对象吗?->{1}", FullName, tp.IsCOMObject); Console.WriteLine("{0}是public访问类型吗?->{1}", FullName, tp.IsPublic); Console.WriteLine("{0}是密封类型吗?->{1}", FullName, tp.IsSealed); Console.WriteLine("{0}是值类型吗?->{1}", FullName, tp.IsValueType); //获取Type对象的所有公共成员并保存到mi数组 MemberInfo[] mi = tp.GetMembers(); //遍历并输出mi数组所有的子项属性 foreach (MemberInfo m in mi) { Console.WriteLine("\t成员类别->{0},名称->{1}",m.MemberType, m.Name); } //获取Type对象所支持的接口并保存到Itp数组 Type[] Itp = tp.GetInterfaces(); //判断Itp数组是否有子项,如果有则输出子项属性 if (Itp.Length != 0) { foreach (Type t in Itp) { Console.WriteLine("{0}实现的接口类型->{1}", FullName, t.FullName); } } else { Console.WriteLine("{0}不实现的任何接口类型", FullName); } } } |
|