1、反射是什么
在程序运行过程中,通过一种技术把程序集(.exe .dll)中的内容全部投射解析出来,这个过程叫反射;比如:在程序运行过程中,知道程序集有哪些方法,哪些类,在运行中实例化对象
C#编译运行过程:
首先我们在VS点击编译的时候,就会将C#源代码编译成程序集
程序集以可执行文件 (.exe) 或动态链接库文件 (.dll) 的形式实现
程序集中包含有Microsoft 中间语言 (MSIL) 和必需的元数据。
元数据存储以下信息:
程序集的说明:标识(名称、版本、区域性、公钥)、导出的类型、该程序集所依赖的其他程序集、运行所需的安全权限。
类型的说明:名称、可见性、基类和实现的接口、成员(方法、字段、属性、事件、嵌套的类型)。
特性:修饰类型和成员的其他说明性元素。
运行时实时 (JIT) 编译器将 MSIL 转换为本机代码
运行代码
反射 来自 System.Reflection命名空间,它可以读取程序集中的元数据,利用元数据创建对象,从而实现各种功能。
注意:区分反射与反编译,反射读取的是元数据,反编译读取的中间代码
2、反射的优缺点
优点:提高了程序的灵活性和扩展性,降低耦合度
缺点:由于反射多了一道程序,性能上相较于直接代码要慢
3、反射的使用
引用命名空间 using System.Reflection;
反射相关的类:
System.Type
System.Reflection.Activator
System.Reflection.Assembly
System.IO.DirectoryInfo
System.IO.FileInfo
1、System.Type类的一些使用
如果type是数据类型,type.FullName 就是数据类型的全名(包含命名空间)
如果type是类,type.FullName 就是类的全名(包含命名空间:命名空间.类)
如果type是程序集,type.FullName 就是程序集的绝对路径
object.GetTypes() 获取Type实例
通过Type类获取程序集、模块、类的相关信息
——Type类是一个抽象类,因此不能用他去实例化对象
——object类中定义了一个GetType方法,因此所有类都可以使用GetType()获取到某一个对象所属类的Type对象(有命名空间的话参数填命名空间.类名)
——通过Type对象可以获取到类中字段、属性、方法、构造函数等信息
2、System.Reflection.Activator类的一些使用
主要用于创建对象的实例
object obj11 = Activator.CreateInstance(type1); //实例化无参构造函数
3、System.Reflection.Assembly类的一些使用
对程序集的名称使用小结
Assembly类中的常用方法:
Assembly.Load() 方法接收一个String或AssemblyName类型作为参数(程序集名),这个参数需要程序集的强名称
(常用)Assembly.LoadFrom() 根据程序集的文件名或路径,加载程序集(绝对路径/相对路径);这个方法会加载此程序集引用的其他程序集
Assembly.LoadFile() 加载指定路径上的程序集文件内容(相对路径),和上面方法的不同之处是这个方法不会加载此程序集引用的其他程序集
4、反射基础知识
通过反射获取指定文件夹下程序集里类的对象
方法1:
//获取路径
string DllPath1 = @"D:\vs项目\项目1\简单工厂练习\反射基础知识\bin\Debug\反射基础.dll";
//加载动态链接库
Assembly assembly = Assembly.LoadFile(DllPath1);
//通过指定名称获取类,将信息存储在Type类上
Type type1 = assembly.GetType("TTEE.Test");
//通过类实例化产生对象
object obj11 = Activator.CreateInstance(type1); //实例化无参构造函数
object obj21 = Activator.CreateInstance(type1, "123"); //实例化有参构造函数
方法2:
//获取路径
string DllPath2 = @"./反射基础.dll";
//加载动态链接库
Assembly assembly2 = Assembly.LoadFrom(DllPath2);
//通过指定名称获取类,将信息存储在Type类上
Type type2 = assembly2.GetType("TTEE.Test");
//通过类实例化产生对象
object obj12 = Activator.CreateInstance(type2); //实例化无参构造函数
object obj22 = Activator.CreateInstance(type2, "123"); //实例化有参构造函数
5、反射的应用
利用反射+Winform+接口 计算加减乘除
思路:
准备工作:接口类库(IOperation)存放操作符和操作数字段,计算结果(方法),加减乘除四个实现接口类库
接口代码:
namespace IOperation
{
public interface Operation
{
string Name { get; set; } //名称
string StrLeftNum { get; set; } //左操作数
string StrRightNum { get; set; } //右操作数
double GetResult(); //计算结果
}
}
1、winform界面制作好
2、创建一个信息存放类(ClassInfo)
namespace 计算器__反射
{
internal class ClassInfo
{
public string Name { get; set; } //接口实现类名称(类名称)
public string DllPath { get; set; } //动态链接库路径
public string ClassFullName { get; set; } //空间名.类名
}
}
3、在主函数bin文件夹下创建一个Tool文件夹,存放加减乘除类库文件
主窗体代码
namespace 计算器__反射
{
public partial class Form1 : Form
{
//保存动态链接库(ClassInfo)信息
List<ClassInfo> list = new List<ClassInfo>();
public Form1()
{
InitializeComponent();
//===================将指定文件夹下的动态链接库信息,保存记录到集合中====================
//1、获取指定路径下的所有dll文件
DirectoryInfo theFolder = new DirectoryInfo("./Tool");
//2、用object.GetFiles()方法把所有dll文件转化成一个FileInfo[]数组
FileInfo[] fieldInfo = theFolder.GetFiles();
//3、遍历FileInfo[]数组,加载dLL文件
foreach (FileInfo item in fieldInfo) //遍历获取文件信息
{
Console.WriteLine(item.Name); //打印所有dLL文件名
if (item.Name.EndsWith(".dll")) //只要动态链接库(item现在是动态链接库,筛选后缀名是.dll的文件)
{
//加载动态链接库,item.FullName(动态链接库的完整路径)
Assembly assembly = Assembly.LoadFrom(item.FullName);
//获取DLL中所有类的信息 assembly.GetTypes() 获取dll所有类的信息并返回成type类数组
foreach (Type type in assembly.GetTypes())
{
Console.WriteLine(type.FullName); //打印类的名称(type.FullName 命名空间.类名)
//实例化子类,使用反射的方式,通过类名实例化类,这里是拆写,全写是Assembly.LoadFrom(item.FullName).CreateInstance(type.FullName);
Operation obj = (Operation)assembly.CreateInstance(type.FullName);
//将类的名称填入到comboBox下拉列表属性中
this.comboBox1.Items.Add(obj.Name); //这里obj.Name是接口实现类的Name属性(+,-,*,/)
//保存遍历到的信息:名称(obj.Name)、动态链接库路径(item.FullName)、类的完整名称(type.FullName)
ClassInfo info = new ClassInfo()
{
Name=obj.Name,
DllPath=item.FullName,
ClassFullName=type.FullName,
};
//保存到集合当中去
this.list.Add(info);
//}
}
}
}
}
private void button1_Click(object sender, EventArgs e)
{
//获取计算类别
string type=this.comboBox1.SelectedItem.ToString();
//在list当中查询到对应的对象
ClassInfo info = list.Find(t=>t.Name==type);
//加载动态链接库,然后实例化类
Operation obj1= (Operation)Assembly.LoadFrom(info.DllPath).CreateInstance(info.ClassFullName);
//赋值控件
obj1.StrLeftNum=this.textBox1.Text;
obj1.StrRightNum = this.textBox2.Text;
//获取计算结果
this.textBox3.Text=obj1.GetResult().ToString();
//释放对象
obj1 = null;
}
}
}