【C#语法】详解C#中的反射(Assembly)机制

一 引言

        反射机制是C#中比较有特色的一种技术。它使我们编程时可以更加灵活,能够通过类或者方法名称能够很方便的构造类和调用方法,虽然有一些微不足道的性能损失。
我们先来看一下反射的定义:
        反射的定义:审查元数据并收集关於它的类型信息的能力,元数据(编辑后的基本数据单元)就是一大堆表,编译器会创建一个类定义表,一个字段定义表,一个方法定义表等,System.Reflection命名空间包含的几个类,允许你反射(解析)这些元数据的代码。
        简单来理解:就是编译器在编译反射相关的代码时,会将所有的类、方法、属性等分别创建一个表,而每个表的元素都对应着一部分元数据中的代码。当我们利用类名称字符串去创建这个类中,程序会在保存类中表中找到我们提供的这个类名称,然后再找到对应的构造函数,并执行。

二、反射中的类型

MemberInfo-反射类的成员
ConstructorInfo-反射类的构造函数
FieldInfo-反射类的字段
MethodInfo-反射类的构造函数的方法
PropertyInfo-反射类的构造函数的属性
EventInfo-反射类的构造函数的事件

三 、反射相关操作

3.1 准备测试环境

        新建一个C#的类库TestDll作为我们要引入的动态链接库,同时新建一个Winform项目RefDll作为我们的主程序。



        在类库中我们添加以下类作为需要用反射引入的类:
public class Test
{
}

3.2 以反射的方式加载dll生成数据集

        我们通过Assembly对象的LoadFrom方法来加载dll,生成数据集对象实例:
string plugin = "TestDll.dll";
Assembly assembly = Assembly.LoadFrom(plugin);
        生成的assembly的就是我们需要的数据集对象,后续所有反射机制的相关操作我们都会在这个对象的基础之上进行,Assembly中还有Load()、LoadFile()其他两个方法来生成数据集信息,区别在这里就不再阐述,自行google或百度。

3.3 获取数据集中所有的数据类型(即我们在dll中定义的类)

Type[] types = assembly.GetTypes();
Type type= types[0];

        因为我们在dll中只定义了一个类,所以这里的types只会有一个元素,我们把它提取出来,是为了后续代码解释起来比较方便,实际编程中往往是需要一个循环进行遍历的。

3.4 构造类对象实例

        我们现在Test类中添加两个构造函数,一个有参,一个无参,我们将以两种不同的形式来创建Test对象:
public class Test
{
private int m_i = 0;
public Test()
{

}
private Test(int i)
{
m_i = i;
}


}

        调用无参构造:
object obj1 = assembly.CreateInstance(type.FullName);
        或者:
object obj1 = Activator.CreateInstance(type);

        调用有参构造:
object[] objs=new object[1];
objs[0]=1;
object obj2 = assembly.CreateInstance(type.FullName, false, BindingFlags.CreateInstance, null, objs, null, null);

        或者:
 
   object obj2 = Activator.CreateInstance(type, objs);


        我们利用了Assembly或者Activator的CreateInstance方法生成对象实例,在调用有参构造函数中,CreateInstance的重载版本使用了几个参数,第二个参数是指查找类名时是否忽略大小写,这里false表示不忽略。第三个参数是搜索的标志位,这里我们要创建类实例,所以使用了BindingFlags.CreateInstance,或者使用BindingFlags.Default也可以。第5个参数,当然就是我们需要传入的构造函数的参数列表。如需详细了解CreateInstance的用法,自行MSDN。

3.5 调用类中的方法

        我们现在Test类中添加一个用来测试的方法:
public void fun1()
{
MessageBox.Show("func1");
}

        我们将利用反射来调用这个方法,首先获取类中所有的方法列表:
MethodInfo[] minfos = type.GetMethods();

        MethodInfo就是类中方法的信息,我们通过遍历,找到我们所需要方法的MethodInfo,然后利用MethodInfo的Invoke或者Type的InvokeMember触发方法。
foreach (MethodInfo me in minfos)
{
if (me.Name == "func1")
{
me.Invoke(obj1, null);
type.InvokeMember(me.Name,BindingFlags.InvokeMethod,null,obj1,null);

}
}

        MethodInfo.Invoke接收两个参数,第一个是我们创建的类对象实例,第二个是调用的方法所传递的参数列表,object[]类型,因为func1的参数为空,所以这里传递了null。Type .InvokeMember有效的参数和MethodInfo.Invoke类似,只不过多了一个过虑标志BindingFlags.InvokeMethod。

3.6 获取类的所有字段

        我们先将Test类中的m_i成员属性改成公有:
public int m_i = 0;

        然后通过下面的代码可以获取m_i字段:
FieldInfo[] finfo = type.GetFields();

3.7 获取类的所有事件

        在Test类中添加如下自定义事件:
//定义委托
public delegate void BtnClickHandle(object sender, EventArgs e);
//定义事件
public event BtnClickHandle UserControlBtnClicked;

        获取定义的该事件:
EventInfo[] einfo = type.GetEvents();

3.8 获取构造函数

ConstructorInfo[] cinfo = type.GetConstructors();

3.9 获取所有成员

MemberInfo[] memInfo = type.GetMembers();


Github位置:
https://github.com/HymanLiuTS/CSGroup
克隆本项目:
git clone git@github.com:HymanLiuTS/ CSGroup.git
获取本文源代码:
git checkout CSL01

发布了301 篇原创文章 · 获赞 158 · 访问量 106万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览