首页 > 代码库 > 反射(2)使用反射

反射(2)使用反射

  这一篇文章来总结下怎么使用反射的。

加载程序集

要加载程序集,可以调用 Assembly的LoadXXX系列方法。

1,Assembly.Load方法

1 //1,从GAC或应用程序基目录加载程序集2 var assembly = Assembly.Load("ReflectionDemo.A, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");//或ReflectionDemo.A也可以

 

需要注意的是:

1)查找顺序,首先去GAC查找,如果没找到,则去应用程序的基目录查找,如果都没找到,则会抛出FileNotFoundException的异常。

2)Load参数一般为应用程序集名称的长格式,如:ReflectionDemo.A, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null,也可以直接ReflectionDemo.A。

 

2,Assembly.LoadFrom方法

1 //2,从一个url加载程序集2 var assembly = Assembly.LoadFrom(@"http://www.a.com/ReflectionDemo.A.dll"); 

 

Assembly.LoadFrom的内部其实是调用Assembly.Load方法,唯一的不同在于,其可以从一个网络url中加载程序集。

 

3,Assembly.LoadFile方法

1 //3,从本地路径加载程序集2 var path = string.Format(@"{0}\{1}", AppDomain.CurrentDomain.BaseDirectory, @"plugins\ReflectionDemo.A.dll");3 var assembly = Assembly.LoadFile(path);

 

Assembly.LoadFile允许从本地不同路径加载程序集。

查找程序集内所有类型

反射的入口Type类,Type对象提供的属性和方法可以获取对明的一切信息,包括:字段,属性,方法和事件等等。

在已经加载了程序集的基础上,能过以下方式可以获取到Type对象。

 1 /// <summary> 2 /// 获取程序集中所有的公共类型 3 /// </summary> 4 /// <param name="assembly"></param> 5 static void GetExportedTypes(Assembly assembly) 6 { 7     var types = assembly.GetExportedTypes(); 8     foreach (var item in types) 9     {10         Console.WriteLine(item.Name);11     }12 }
1 /// <summary>2 /// 获取程序集中具名的类型3 /// </summary>4 /// <param name="assembly"></param>5 static void GetType(Assembly assembly)6 {7     var t = assembly.GetType("ReflectionDemo.A.Class1");8     Console.WriteLine(t.Name);9 }

 

 

查找类型成员

在命名空间System.Reflection下有一个抽象类MemberInfo,它封装了与类型成员相关的通用属性,每一个类型成员都有一个对应的从MemberInfo派生而来的类型,并且内置了一些特殊的属性特征,如FieldInfo、MethodBase(ContructorInfo、MethodInfo)、PropertyInfo和EventInfo。可以通过调用类型Type对象的GetMembers方法获取该类型的所有成员或相应成员,如下代码(对上面的GetTypes方法的修改)获取全部成员列表:

 1 /// <summary> 2 /// 获取类型成员 3 /// </summary> 4 /// <param name="t"></param> 5 static void GetMembers(Type t) 6 { 7     var members= t.GetMembers(); 8     foreach (var item in members) 9     {10         Console.WriteLine(item.Name);11     }12 }

 

Type对象有一组GetXXX方法是用来获取对象成员的,如下:

GetConstructor/GetConstructors //获取构造函数GetField/GetFields //获取字段GetProperty/GetProperties //获取属性GetMethod/GetMethods //获取方法GetEvent/GetEvents //获取事件

 

看下MemberInfo的结构:

技术分享

构造类型实例

拿到类型和成员相关信息后,就可以创建类型的实例了,创建类型实例有以下几种方法:

1 Activator.CreateInstance() //重载系列2 Activator.CreateInstanceFrom() //重载系列3 AppDomain.CurrentDomain.CreateInstance() //重载系列4 AppDomain.CurrentDomain.CreateInstanceFrom() //重载系列

 

下面就来创建一个ReflectionDemo.A.Class1的实例(对象),如下代码:

1 /// <summary>2 /// 创建类型实例3 /// </summary>4 static void CreateInstance(Assembly assembly)5 {6     var t = assembly.GetType("ReflectionDemo.A.Class1");7     var obj = Activator.CreateInstance(t);8 }

 

 

访问实例成员

创建了类型的实例后,就可以调用实例的成员方法了,如下代码:

 1 /// <summary> 2 /// 动态调用方法 3 /// </summary> 4 /// <param name="assembly"></param> 5 static void InvokeMethod(Assembly assembly) 6 { 7     var t = assembly.GetType("ReflectionDemo.A.Class1"); 8     var obj = Activator.CreateInstance(t); 9 10     var name = t.InvokeMember("GetName", BindingFlags.InvokeMethod, null, obj, null);11 }

 

上面演示了动态调用实例成员,访问实例其它成员可以通过BindingFlags来改变。

 

反射对泛型的支持

前面演示的都是普通类型,如果是泛型,该怎么处理呢?

首先定义一个泛型类,如下:

 1 namespace ReflectionDemo.A 2 { 3     public class Class2<T> where T : class 4     { 5         public string GetName<T>(T name) 6         { 7             return string.Format("generic name,{0}", name.ToString()); 8         } 9     }10 }

 

演示一下如何调用泛型类的GetName方法,如下代码:

 1 /// <summary> 2 /// 访问泛型类型成员 3 /// </summary> 4 /// <param name="assembly"></param> 5 static void InvokeGenericMethod(Assembly assembly) 6 { 7     var types = assembly.GetExportedTypes(); 8     foreach (var item in types) 9     {10         if (item.IsGenericType)//1,先判断是否为泛型11         {12             var obj = Activator.CreateInstance(item.MakeGenericType(new Type[] { typeof(string) }));//2,在创建泛型类实例前,必须调用MakeGenericType创建一个真正的泛型13             var methodInfo = obj.GetType().GetMethod("GetName").MakeGenericMethod(new Type[] { typeof(string) });//3,在调用泛型方法前,必须调用MakeGenericMethod创建一个真正的泛型方法14 15             var name = methodInfo.Invoke(obj, new object[] { "aaa" });16             Console.WriteLine(name);17         }18     }19 }

 

反射(2)使用反射