反射就是使用System.Reflection命名空间下的方法来操作DLL文件。
使用方法及步骤:
一、加载Dll文件
方式一:使用Assembly.Load
这个文件要放在启动项目Debug目录下(例如:E:\ App\bin\Debug),也可以通过添加引用的方式添加。
Assembly assembly1=Assembly.Load("DLL文件的名称");//不用加.后面的扩展名
方式二:使用Assembly.LoadFile
使用完整路径,例如:E:\ App\bin\Debug\XXX.dll
Assembly assembly2=Assembly.LoadFile(@"DLL文件的完整路径");
(常用)方式三:使用Assembly.LoadFrom
使用完整路径 或者 DLL文件的名称+扩展名,前两种的结合,一般用这种
Assembly assembly3=Assembly.LoadFrom(@"DLL文件的完整路径 或者 DLL文件的名称+扩展名");
二、如果不知道DLL文件中有哪些类型
可以通过遍历获取所有的类型名称
foreach(var item in assembly)//查找所有的类型
{
Console.WriteLine(item.Name); //打印类型的名字
}
三、获取指定类型
假设我们知道要获取的类型是 "Namespace.ClassName"(命名空间+类名)
Type type = assembly3.GetType("Namespace.ClassName");
四、获取指定类型中的构造方法和参数
//BindingFlags.Instance|BindingFlags.NonPubli是根据想要获取的方法的类型添加标签,这里是获取私有的构造方法
foreach(var ctor in type.GetConstructors(BindingFlags.Instance|BindingFlags.NonPublic))//
{
Console.WriteLine($"构造方法:{ctor.Name}"); // 获取构造方法,因为构造方法名字和类名一样,这里只会打印一个点
//获取构造方法的参数
foreach(var param in ctor.GetParameters)
{
Console.WriteLine($"构造方法参数:{param.ParameterType}"); // 获取构造方法参数
}
}
五、创建类型的实例
创建类型的实例,因为返回值是object类型,所用object来接
第一种:构造方法没有参数
object instance = Activator.CreateInstance(type);//动态实例化
第二种:构造方法有参数
object instance = Activator.CreateInstance(type,new object[] { 参数1, 参数2 });//动态实例化
第三种:调用私有无参数数构造函数,添加标签
object instance = Activator.CreateInstance(
type,
BindingFlags.Instance | BindingFlags.NonPublic,
null,
new object[] { },
null
);
第四种:调用私有有参数数构造函数,添加标签
object instance = Activator.CreateInstance(
type,
BindingFlags.Instance | BindingFlags.NonPublic,
null,
new object[] { 参数1, 参数2 },
null
);
六、调用类型的公开方法
调用普通方法,用.加方法名就可以了,比如有一个Show1的普通方法
//调用方法前需要将instance转换为具体的类,使用as不报错,转换失败返回空,也可用其它方式
ClassName feflectionTest=instance as ClassName;//(具体类名+新名字=原名 as 具体类名)
feflectionTest.Show1();
七、调用类型的私有方法
//【*】调用私有方法
//已经知道了方法的名字J叫Show2,然后通过名字找到这个方法
//不能用instance和feflectionTest,要用最开始的type
//添加查找标签:实例的|不公开的
var method=typ.GetMethod("Show2",BindingFlags.Instance|BindingFlags.NonPublic);
//调用方法
//没有参数{}中就不填,
//参数数组 new object[]{ 42, "Hello", 3.14 }
//中的每个元素对应方法的一个参数,顺序必须与方法定义中的参数顺序一致。
method.Invoke(instance,new object[]{});//instance在上面第五项中定义
八、调用类型的泛型方法
可以使用第六项,调用公开方法的方式调用,也可以使用以下这种
//假如知道方法的名字叫Show3
//按名字找到方法
var method = type.GetMethod("Show3");//查找指定的类型
var genericMethod=method.MakeGenericMethod(new Type[]{typeof(int)});//指定泛型参数类型T
genericMethod.Invoke(instance,new object[]{参数1, 参数2});//instance在上面第五项中定义
九、泛型类+泛型方法
1.加载DLL文件
Assembly assembly=Assembly.LoadFrom(@"DLL文件的完整路径或者DLL文件的名称+扩展名");
2.获取指定泛型类,例如在SqlServerDB命名空间下有一个GenericClass<T,W>类
Type type=assembly.GetType("SqlServerDB.GenericClass`2").MakeGenericType(type(int),type(string));
解释:"SqlServerDB.GenericClass`2"中"`2"的意思是有两个参数<T,W>,有几个参数就是几,type(int),type(string)是用来指定这两个参数的。
3.实例化类
object objTest=Activator.CreateInstance(type);
4.方法调用,假如有一个public void GenericMethod<t>();方法
通过方法名获取方法,并指定t为int
var method=type.GetMethod("GenericMethod").MakeGenericMethod(typeof(int));
调用获取到的方法
method.Invoke(objTest.new object[]{});
十、操作属性
定义以下几个属性用做实验
1.加载DLL文件
Assembly assembly=Assembly.LoadFrom(@"DLL文件的完整路径或者DLL文件的名称+扩展名");
2.获取指定泛型类,例如在SqlServerDB命名空间下有一个PropertyClass类
Type type=assembly.GetType("SqlServerDB.PropertyClass");
3.实例化类
object objTest=Activator.CreateInstance(type);
4.获取所有属性的名称
foreach(var property in type.GetProperties())
{
Console.WriteLine(property.Name);
//设置指定名称的属性的值,例如设置ID的值
if(property.Name.Equals("Id"))//Equals是用来判定是否相等的方法
{
property.SetValue(objTest,1);//设置为1
}
else if(property.Name.Equals("Name"))
{
property.SetValue(objTest,"小明");
}
else if(property.Name.Equals("Phone"))
{
property.SetValue(objTest,"1234567890");
}
//获取属性的值
Console.WriteLine(property.GetValue(objTest));
}