程序集
程序集是经由编译器编译得到,供进一步编译执行的那个中间产物,在Windows系统中一般是后缀为.dll的库文件或者.exe的可执行文件
即我们所写的代码被编译器编译后得到的供人使用的代码集合
元数据
有关程序及其类型的数据被称为元数据,比如程序中的类、类中的函数、变量等等信息就是程序的元数据,保存在程序集中
反射的概念
程序在运行时可以查看其他程序集或者自身的元数据,这个查看的行为叫做反射
即在程序运行时,通过反射可以得到其他程序集或者自身程序集代码的各种信息,如类、函数、变量、对象等等,能够实例化、执行、操作它们
反射的作用
由于反射可以在程序编译后获得信息,他提高了程序的拓展性和灵活性。
在程序运行时获取所有的元数据,包括元数据的特性
程序运行时实例化对象操作对象
程序运行时创建新的对象用这些对象执行任务
语法相关
Type
类的信息类,是反射的基础,是访问数据的主要方式,使用Type的成员获取有关类型声明的信息,有关类型的成员(如:构造函数、方法、字段、属性和类的事件)
获取Type
//通过Object中的GetType()来的到对象的type
int a = 1;
Type type = a.GetType();
Console.WriteLine(type);
//通过typeof()关键字传入类名也能得到对象的type
Type type1 = typeof(int);
//用过类名也能获取type
//注意类名必须包含命名空间,不然找不到
//Type type2 = Type.GetType("Int32"); 这样不行
Type type2 = Type.GetType("System.Int32");
Console.WriteLine(type2);
Console.WriteLine(type1);
得到类的程序集信息
System.Console.WriteLine(type.Assembly);
获取类中的公共成员
class Test
{
private int i = 1;
public int j = 0;
public string s = "123";
public Test() { }
public Test(int i)
{
this.i = i;
}
public Test(int i, string s) : this(i)
{
this.s = s;
}
public void Speak()
{
Console.WriteLine(i);
}
}
得到type
Type t = typeof(Test)
得到所有的公共成员(需要引用命名空间using System.Reflection)
MemberInfo[] infos = t.GetMembers();
for(int i = 0; i < infos.Length; i++)
{
Console.WriteLine(infos[i]);
}
得到所有构造函数
ConstructorInfo[] constructors = t.GetConstructors();
for(int i=0; i < constructors.Length; i++)
{
Console.WriteLine(constructors[i]);
}
获取其中一个构造函数并执行
得到构造函数要传入Type数组,数组中的内容按顺序是构造函数的参数类型
执行构造函数要传入Object数组,表示按顺序传入的参数
无参构造:
ConstructorInfo info = t.GetConstructor(new Type[0]);
Test obj = info.Invoke(null) as Test;//没有参数传入null
Console.WriteLine(obj.j);
有参构造:
ConstructorInfo info1 = t.GetConstructor(new Type[] { typeof(int) });
obj = info1.Invoke(new object[] { 3}) as Test;
Console.Write(obj.s);
ConstructorInfo info2 = t.GetConstructor(new Type[] {typeof(int),typeof(string) });
obj = info2.Invoke(new object[] { 4,"44444" }) as Test;
Console.WriteLine(obj.s);
获取类中的公共成员变量
获取所有公共成员变量:
FieldInfo[] fieldInfos = t.GetFields();
for(int i = 0;i < fieldInfos.Length;i++)
{
Console.WriteLine(fieldInfos[i]);
}
得到指定名称的公共成员变量
FieldInfo infoj = t.GetField("j");
Console.WriteLine(infoj);
通过反射获取和设置对象的值
Test test = new Test();
test.j = 111;
test.s = "ssss";
Console.WriteLine(infoj.GetValue(test));
infoj.SetValue(test, 222);
Console.WriteLine(infoj.GetValue(test));
获取和调用类的公共成员方法
Type strType = typeof(string);
MethodInfo[] methods = strType.GetMethods();
for(int i = 0; i < methods.Length;i++)
{
Console.WriteLine(methods[i]);
}
MethodInfo subStr = strType.GetMethod("Substring",
new Type[] {typeof(int),typeof(int)});//如果存在重载通过Type数组中的内容进行区分
string str = "Hello,World!";
//调用方法,如果是静态方法Invoke中第一个参数传null,因为不需要对象来调用该方法
Object res = subStr.Invoke(str, new object[] { 7, 5 });
Console.WriteLine(res);
Assembly
程序集类,主要用来加载其他程序集,加载后才能用Type来使用其他程序集中的信息
若要使用非自身程序集中的内容,要先加载程序集,如dll文件(库文件,可以看成一个代码仓库,她提供给我们一些可以直接拿来使用的变量、函数或类)
三种加载程序集的函数
一、一般用来加载同一文件夹下的其他程序集
Assembly assembly = Assembly.Load();//参数为 程序集名称
二、一般用来加载在不同文件夹下的其他程序集
Assembly assembly1 = Assembly.LoadFrom();//参数为 路径+dll文件名
Assembly assembly2 = Assembly.LoadFile();//参数为 要加载的文件的完全限定路径
@可以取消转义字符
加载一个指定数据集
Assembly assembly1 = Assembly.LoadFrom();
加载数据集中的类对象
//例举有什么类
Type[] types = assembly1.GetTypes();
for(int i = 0;i < types.Length;i++)
{
Console.WriteLine(types[i]);
}
Type icon = assembly1.GetType("***.Icon");//加载***环境下的Icon类
//例举该类下有什么成员
MemberInfo[] members = icon.GetMembers();
for(int i = 0; i < members.Length;i++)
{
Console.WriteLine(members[i]);
}
实例化类对象
由于Icon构造函数中有用到另外一个在该数据集中的枚举,故若要实例化一个Icon对象就得先实例化该枚举对象
Type moveDir = assembly1.GetType("***.MoveDir");
FieldInfo right = moveDir.GetField("Right");
//由于枚举没有对象,故可以通过right.getValue(null)来得到枚举
object iconObj = Activator.CreateInstance(icon,10,5,right);
通过反射得到对象中的方法
clear.Invoke(iconObj, null);
Activator
用于快速实例化对象的类,用于将Type对象快捷实例化为对象,先得到Type然后快速实例化一个对象
Type testType = typeof(Test);
无参构造
Test testObj = Activator.CreateInstance(testType) as Test;
Console.WriteLine(testObj);
有参构造
类型后面的参数就是构造函数中的参数,要一一对应不然会报错
testObj = Activator.CreateInstance(testType, 11) as Test;
Console.WriteLine(testObj);
testObj = Activator.CreateInstance(testType, 11,"123") as Test;
Console.WriteLine(testObj);
应用
新建一个类库工程,内有Player类,内含姓名构造函数等信息
Assembly assembly3 = Assembly.LoadFrom(@"***");//路径+dll文件名,后缀可加可不加
Type[] t1 = assembly3.GetTypes();
for(int i = 0; i < t1.Length; i++)
{
Console.WriteLine(t1[i]);
}
Type player = assembly3.GetType("***.Player");
Object objplayer = Activator.CreateInstance(player);
Console.WriteLine(objplayer);