反射使用反射

Posted mcgrady

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了反射使用反射相关的知识,希望对你有一定的参考价值。

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

加载程序集

要加载程序集,可以调用 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 }

 

以上是关于反射使用反射的主要内容,如果未能解决你的问题,请参考以下文章

反射机制

反射机制入门

反射机制入门

反射机制入门

将 OpenGL 片段着色器设置为仅通过漫反射减少 vec4 色点的 RGB 值,而不是 alpha

Golang实践录:反射reflect的一些研究及代码汇总