反射的作用
个人总结一下:反射只要是获取别的程序集的类,方法,变量等等,程序集就是一个项目中的 .dll 文件,可以通过反射来获取该文件中的东西
反射的基础Type
我们先写一个类,来通过该例子讲解Type,初步了解反射的作用
注意:下面声明的t4反射的是Test类,后面防止大家忘记t4是什么东西,先声明一下
class Test
{
public int testa=20;
protected int tes;
public string str;
private int testb;
public Test()
{
Console.WriteLine("我是Test无参构造函数");
}
public Test(int a)
{
Console.WriteLine("我是Test有参构造函数,只有一个int类型参数的构造函数");
}
public Test(int a, string b)
{
this.str = b;
this.testa = a;
Console.WriteLine("我是Test有参构造函数,有一个int类型参数,一个string类型参数的构造函数");
}
public void say()
{
Console.WriteLine("我是Test的Say函数");
}
}
1获取Type
想用反射,我们首先先得到Type类
1-1 万物之父Object.GetType()
int a = 20;
Type t1 = a.GetType();
Console.WriteLine(t1);
运行结果:
这里输出t1,输出的是Int类型的命名空间和类名字。该方法通常用在已经得到的对象再进行反射
1-2 typeof方法
Type t2 = typeof(string);
Console.WriteLine(t2);
运行结果:
该方法通常是用在已经知道的类,比如int,string,char等等…
1-3 用命名空间来获取., 名字格式:命名空间名.类的名字
Type t3=Type.GetType("System.String");
Console.WriteLine(t3);
运行结果:
该方法通常用在同一项目里,但是不同文件中的项目类。
比如在同一项目中,你有两个类文件,你想从第一个类文件中调用另一个类文件中的类或者方法就可用该反射方法。
2.获取类的程序集信息
Console.WriteLine(t1.Assembly);
直接调用Assembly方法就可以。
运行结果:
该方法了解即可,基本不用
3.获取类的公共成员
通过反射得来的类,我们只能访问公共成员,必须是public的, protected也是不可以的
获取所有的公共成员,包括构造函数,变量,函数…
Console.WriteLine("****获取类的公共成员*********");
Type t4 = typeof(Test);
MemberInfo[] memberInfos = t4.GetMembers();//用MemberInfo来接收返回的的方法,因为只能接受一个,所以要用数组的形式来接收,这里返回的是所有的,用了GetMembers()。
for (int i = 0; i < memberInfos.Length; i++)
{
Console.WriteLine(memberInfos[i]);
}
运行结果:
第一个是Test中声明的方法,后面两个是声明的公共变量。
4.获取构造函数
Console.WriteLine("****获取构造函数*********");
ConstructorInfo[]m= t4.GetConstructors();//和上面的同理,返回所有的
for (int i = 0; i <m.Length; i++)
{
Console.WriteLine(m[i]);
}
运行结果:
这里的构造函数同意用ctor来表示,其中的参数是参数类型,和上面声明的Test类的三个构造函数对应。
4-1 使用无参构造函数
ConstructorInfo nullConstructorInfo = t4.GetConstructor(new Type[0]);
nullConstructorInfo.Invoke(null);//该Invoke是调用函数的api,里面的参数要求是一个object实例,并传入相应的数据类型的参数,因为是无参构造函数,所以用null表示。
Test test1 =nullConstructorInfo.Invoke(null) as Test;
这里用的GetConstructor方法,里面的参数是声明有什么类型的参数,这个newType[0]数组说明有0个参数,也就说明是无参构造函数
运行结果:
4-2 使用有参构造函数
ConstructorInfo haveConstructorInfo = t4.GetConstructor(new Type[] {typeof(int)});
haveConstructorInfo.Invoke(new object[] {2});
Test test2=haveConstructorInfo.Invoke(new object[]{2}) as Test;
这里的因为有一个int类型的参数,所以第一句代码要有参数集合,所以定义一个数组,里面声明该数组的参数类型,其参数类型要用typeof(参数类型),第二句代码中的参数是要声明一个空物体参数是int类型,添加一个2
运行结果:
5.获取公共成员变量
5-1 获取所有的公共变量
FieldInfo[] fieldInfos = t4.GetFields();
for (int i = 0; i < fieldInfos.Length; i++)
{
Console.WriteLine(fieldInfos[i]);
}
运行结果:
5-2 得到指定名称的公共成员变量
FieldInfo fieldInfo = t4.GetField("str");
Console.WriteLine(fieldInfo);
运行结果:
5-3 通过反射获取和设置对象的值
Test t5 = new Test();
t5.testa = 99;
t5.str = "哈啊哈";
//这里的fieldInfo上个代码块的变量
Console.WriteLine(fieldInfo.GetValue(t5));//得到该变量反射对象的值,第一个参数是反射对象
fieldInfo.SetValue(t5,"修改的信息");
Console.WriteLine(fieldInfo.GetValue(t5));//设置反射对象的值
运行结果:
6.获取公共成员方法
Console.WriteLine("***********获取公共成员方法***********");
Type strType = typeof(string);//获取string的所有的公共成员方法
MethodInfo[] methodInfos = strType.GetMethods();
for (int i = 0; i < methodInfos.Length; i++)
{
Console.WriteLine(methodInfos[i]);
}
运行结果:
一大堆哈…
6-1 获取名义成员方法
MethodInfo method = strType.GetMethod("Substring", new Type[] {typeof(int), typeof(int)});
这里的参数填写 第一个参数是想要获取方法的名字 第二个是指参数类型,用一个Type数组来说明
6-2 调用该方法
注意:如果是静态方法 Invoke中的第一个参数传null即可
第一个参数是那一个对象执行该方法
Console.WriteLine("***********调用该方法***********");
string str = "pixuezhazhenshaui";
var endStr= method.Invoke(str, new object[]{4,5});
Console.WriteLine(endStr);
获取的是切割方法,Invoke传的参数和对象
运行结果:
反射Activator
用于快速实例化对象的类
用于将Type对象快捷实例化为对象
先得到Type
然后快速实例化一个对象
先声明一个Testl类
class Testl
{
public int a;
public string str;
public Testl()
{
Console.WriteLine("我是无参构造函数");
}
public Testl(int a, string b)
{
this.a = a;
this.str = b;
Console.WriteLine("参数是int"+a+" string"+str);
Console.WriteLine("我是有参构造函数");
}
public void say()
{
Console.WriteLine("我是公共成员函数");
}
}
用Activator实例化对象
无参构造函数实例化对象
Type teType = typeof(Testl);
Testl test=Activator.CreateInstance(teType) as Testl;
运行结果:
有参数实例化对象
Testl haTest=Activator.CreateInstance(teType,20,"hahaah") as Testl;
haTest.say();
运行结果:
这里实例化函数第一个参数是反射对象,后面的跟构造函数的参数。
为什么这样用
看完上面两个实例化过程有人可能疑问,我们明明声明了Testl类,我们直接new一个不就行了吗?那里用的着反射的,这不是多此一举吗?确实,这样做事多此一举,我这样写是想告诉你该Activator如何实例化的,下面才是为什么反射用它实例化。
Assembly
作用用处
用该反射是调用别的项目文件里的程序集,上面的知识都是为了该篇章做铺垫,终于可以真正的认识到反射的作用了。
注意事项
程序集类
主要用来加载其它程序集,加载后
才能用Type来使用其它程序集中的信息
如果想要使用不是自己程序集中的内容需要先加载程序集
比如dll文件(库文件)
简单的把库文件看成一种代码仓库,它提供给使用者一些可以直接拿来用的变量、函数或类
三种加载程序集的函数
一般用来加载在同一文件下的其它程序集
Assembly asembly2 = Assembly.Load(“程序集名称”);
一般用来加载不在同一文件下的其它程序集
Assembly asembly = Assembly.LoadFrom(“包含程序集清单的文件的名称或路径”);
Assembly asembly3 = Assembly.LoadFile(“要加载的文件的完全限定路径”);
1.加载一个指定程序集
Assembly assembly=Assembly.LoadFrom(@"D:\桌面文件夹\vs项目工程\cshape学习项目集合\反射type\bin\Debug\netcoreapp3.1\反射type");
Type[] types = assembly.GetTypes();
for (int i = 0; i < types.Length; i++)
{
Console.WriteLine(types[i]);
}
该文件夹需要自己设置路径,记住是dll文件
这是我的两个文件,反射的是反射type项目中的dll文件
运行结果:
type只反射dll文件中的类
2.再加载程序集中的一个类对象 之后才能使用反射
Console.WriteLine("************再加载程序集中的一个类对象 之后才能使用反射**************");
Type type = assembly.GetType("反射type.Test");
MemberInfo[] memberInfos = type.GetMembers();
for (int i = 0; i < memberInfos.Length; i++)
{
Console.WriteLine(memberInfos[i]);
}
用assembly.GetType直接反射当中的某一个类即可。
运行结果:
3.通过反射,实例化一个Test对象
object o = Activator.CreateInstance(type, 50, "hahah") as object;//实例化处一个对象
这里用到了 Activator,所以获取别的项目中的程序集,我们首先获取一个type,就要用到Assembly,获取type后就可以用 Activator来快速实例化。
已经实例化成功。
4.得到对象中的方法并调用
Console.WriteLine(fieldInfo.GetValue(o));
Console.WriteLine(o);
MethodInfo say = type.GetMethod("say");
say.Invoke(o, null);
运行结果:
第一个返回o中的testa的值,第二个说o的名字,第三个是调用say函数。