C#--反射基础
以下是学习笔记:
一,反射的基本信息
DLL/EXE: 主要区别EXE文件有一个入口,DLL文件不能运行,但是DLL能拿到其他地方去使用
metadata(元数据):描述exe/dll文件的一个清单,记录了exe/dll文件中有哪些类,属性,特性,字段。。。
Reflection(反射):用来操作或获取元数据metadata
有什么作用:
1,更新程序(更新自己的DLL)
一个工程有多个项目,更新其中一个小项目,就是替换一个dll文件就可以了
2,使用别人的DLL文件(这种可以读取别人的私有的东西)
反射是什么:就是一个操作metadata的一个类库(可以把反射当成一个小工具,用来读取或操作元数据的)
使用场景:asp.net MVC ,ORM,LOC,AOP,几乎所有的框架都会使用反射
二,通过反射加载DLL文件
代码:
//加载方式一,dll文件名(当前目录) //Assembly assembly=Assembly.Load("Ant.DB.SQLServer"); //加载方式二,dll文件的完整路径(文件具体路径) //Assembly assembly=Assembly.LoadFile(@"E:\VS workspace\学习 单个项目\反射\MyReflection\Ant.DB.SQLServer\bin\Debug\Ant.DB.SQLServer.dll"); //加载方式三,dll文件的完全限定名(当期目录) //Assembly assembly=Assembly.LoadFrom("Ant.DB.SQLServer.dll"); //加载方式四,跟上面是一样的,只是参数不一样(文件具体路径) Assembly assembly =Assembly.LoadFrom(@"E:\VS workspace\学习 单个项目\反射\MyReflection\Ant.DB.SQLServer\bin\Debug\Ant.DB.SQLServer.dll"); //注意:方式一的文件是当前目录的,因为在引用里面添加了项目的。 // 如果第三方的需要复制到项目里面,或者用文件具体路径 foreach (var type in assembly.GetTypes())//找所有类型 { Console.WriteLine(type.Name); foreach (var method in type.GetMethods())//找所有方法 { Console.WriteLine("这是:"+method.Name+" 方法"); } }
注意:
三,通过反射创建对象
1,使用反射创建对象(无参数的构造函数)
//【1】加载DLL文件 Assembly assembly2 =Assembly.LoadFrom("Ant.DB.SQLServer.dll"); //【2】DLL文件中有很多类型,获取类型(要完整的类型名称) //Type type2 = assembly2.GetType("MySQLServerHelper");//只写一个类名是不行的 Type type2 = assembly2.GetType("Ant.DB.SQLServer.MySQLServerHelper");//需要 命名空间.类名 //【3】创建对象 object oDbHelper = Activator.CreateInstance(type2); //上面等同于 MySQLServerHelper mySqlServerHelper=new MySQLServerHelper(); IDBHelper dBHelper=oDbHelper as IDBHelper;//类型转换(as转换不报错,类型不对就返回null) //IDBHelper dBHelper2 =(IDBHelper)oDbHelper;//不用as转换,类型不对就报错 //【4】调用对象的方法 dBHelper.Query();
2,使用反射创建对象(带参数的构造函数)
//【1】加载DLL文件 Assembly assembly3 = Assembly.LoadFrom("Ant.DB.SQLServer.dll"); //【2】DLL文件中有很多类型,获取类型(要完整的类型名称) Type type3 = assembly3.GetType("Ant.DB.SQLServer.ReflectionTest");//需要 命名空间.类型名称 //获取到这个类型下面的所有构造方法 foreach (ConstructorInfo ctor in type3.GetConstructors())//获取所有的构造方法 { Console.WriteLine(ctor.Name); foreach (var parameter in ctor.GetParameters())//获取构造方法的所有参数类型 { Console.WriteLine(parameter.ParameterType);//显示类型名称 } } //【3】创建对象 object oDbHelper3_1 = Activator.CreateInstance(type3);//无参数的构造函数 object oDbHelper3_2 = Activator.CreateInstance(type3,new object[]{"Ant 编程"});//有1个参数的构造函数 object oDbHelper3_3 = Activator.CreateInstance(type3,new object[]{123});//有1个参数的构造函数 object oDbHelper3_4 = Activator.CreateInstance(type3,new object[]{123,"Ant 编程"});//有2不同类型的参数的构造函数
结果:
3,使用反射创建对象(私有的构造函数)
Console.WriteLine("---------------------------UseReflection 使用反射创建对象(私有的构造函数)-------------------------"); //PrivateCtor privateCtor=new PrivateCtor();//私有构造函数,这样创建直接报错的 //【1】加载DLL文件 Assembly assembly4 = Assembly.LoadFrom("Ant.DB.SQLServer.dll"); //【2】DLL文件中有很多类型,获取类型(要完整的类型名称) Type type4 = assembly4.GetType("Ant.DB.SQLServer.PrivateCtor");//需要 命名空间.类型名称 //【3】创建对象 object oPrivate = Activator.CreateInstance(type4, true);//需要参数2,true,就可以创建私有构造函数的对象啦 //这个功能 还用在我们的单例模式里面(一个对象只能创建一次) 。这个也叫反射破坏单例模式。
四,通过反射创建创建泛型类
1,使用反射创建泛型类
泛型类:
namespace Ant.DB.SQLServer { /// <summary> /// 泛型类 /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="W"></typeparam> /// <typeparam name="S"></typeparam> public class GenericClass<T,W,S> { } }
Console.WriteLine("---------------------------UseReflection 使用反射创建泛型类-------------------------"); //【1】加载DLL文件 Assembly assembly5 = Assembly.LoadFrom("Ant.DB.SQLServer.dll"); //【2】DLL文件中有很多类型,获取类型(要完整的类型名称) //Type type5 = assembly5.GetType("Ant.DB.SQLServer.GenericClass");//需要 命名空间.类型名称 Type type5 = assembly5.GetType("Ant.DB.SQLServer.GenericClass`3");//反单引号+参数的个数(3就是3个泛型类型的参数个数) //把参数类型给上面的type5 Type makType= type5.MakeGenericType(new Type[] {typeof(int), typeof(string), typeof(double)});//typeof(int)获取到类型的具体类型 //【3】创建泛型类的对象 object oGeneric = Activator.CreateInstance(makType);
使用反射创建泛型类的注意事项:
五,通过反射调用方法
1,类的方法代码:
namespace Ant.DB.SQLServer { class ReflectionTest { public ReflectionTest() { Console.WriteLine($"这是{this.GetType()}无参数的构造函数"); } public ReflectionTest(string name) { Console.WriteLine($"这是{this.GetType()}有参数的构造函数,类型为{name.GetType()}"); } public ReflectionTest(int id) { Console.WriteLine($"这是{this.GetType()}有参数的构造函数,类型为{id.GetType()}"); } public ReflectionTest(int id,string name) { Console.WriteLine($"这是{this.GetType()}有参数的构造函数,类型为{id.GetType()}和{name.GetType()}"); } public void Test1() { Console.WriteLine($"这里是{this.GetType()}的Test1"); } public void Test2(int id) { Console.WriteLine($"这里是{this.GetType()}的Test2"); } public void Test3(int id,string name) { Console.WriteLine($"这里是{this.GetType()}的Test3-1"); } public void Test3(string name, int id) { Console.WriteLine($"这里是{this.GetType()}的Test3-2"); } public void Test3( int id) { Console.WriteLine($"这里是{this.GetType()}的Test3-3"); } public void Test3(string name) { Console.WriteLine($"这里是{this.GetType()}的Test3-4"); } public void Test3() { Console.WriteLine($"这里是{this.GetType()}的Test3-5"); } //私有方法 private void Test4(string name) { Console.WriteLine($"这里是{this.GetType()}的Test4的私有方法"); } //静态方法 public static void Test5(string name) { Console.WriteLine($"这里是{typeof(ReflectionTest)}的Test5的静态方法"); } } }
2,使用反射调用方法:
Console.WriteLine("---------------------------UseReflection 使用反射调用方法-------------------------"); //【1】加载DLL文件 Assembly assembly6 = Assembly.LoadFrom("Ant.DB.SQLServer.dll"); //【2】DLL文件中有很多类型,获取类型(要完整的类型名称) Type type6 = assembly6.GetType("Ant.DB.SQLServer.ReflectionTest");//需要 命名空间.类型名称 //【3】创建对象 object oReflection = Activator.CreateInstance(type6);//无参数的构造函数 //获取类型的所有方法和参数 foreach (var method in type6.GetMethods()) { Console.WriteLine("方法:"+method.Name); foreach (var parameters in method.GetParameters()) { Console.WriteLine("参数名:"+parameters.Name+",参数类型:"+parameters.ParameterType); } } { //【4】获取方法 //1,通过方法名来调用方法 MethodInfo methodInfo = type6.GetMethod("Test1"); //【5】调用无参数的方法 methodInfo.Invoke(oReflection, null); } { MethodInfo methodInfo = type6.GetMethod("Test2"); //调用带参数的方法 methodInfo.Invoke(oReflection, new Object[]{123456}); } { //带参数的重载方法 MethodInfo methodInfo = type6.GetMethod("Test3",new Type[]{typeof(int),typeof(string)});//重载方法注意:指定参数类型 methodInfo.Invoke(oReflection, new Object[] { 123456,"jason" });//传入参数类型 } { MethodInfo methodInfo = type6.GetMethod("Test3", new Type[] { typeof(string), typeof(int) }); methodInfo.Invoke(oReflection, new Object[] { "jason" ,123456}); } { MethodInfo methodInfo = type6.GetMethod("Test3", new Type[] { typeof(int) }); methodInfo.Invoke(oReflection, new Object[] { 123456 }); } { MethodInfo methodInfo = type6.GetMethod("Test3", new Type[] { typeof(string) }); methodInfo.Invoke(oReflection, new Object[] { "jason"}); } { //无参数的重载方法 MethodInfo methodInfo = type6.GetMethod("Test3", new Type[] {}); methodInfo.Invoke(oReflection, null); } { //静态方法的调用方式1 MethodInfo methodInfo = type6.GetMethod("Test5"); methodInfo.Invoke(oReflection, new object[]{"jason"}); } { //静态方法的调用方式2 MethodInfo methodInfo = type6.GetMethod("Test5"); methodInfo.Invoke(null, new object[] { "jason" });//静态方法,对象可以为空 }
结果:
3,通过反射调用私有方法
Console.WriteLine("---------------------------UseReflection 使用反射调用私有方法-------------------------"); //【1】加载DLL文件 Assembly assembly7 = Assembly.LoadFrom("Ant.DB.SQLServer.dll"); //【2】DLL文件中有很多类型,获取类型(要完整的类型名称) Type type7 = assembly7.GetType("Ant.DB.SQLServer.ReflectionTest");//需要 命名空间.类型名称 //【3】创建对象 object oReflection7 = Activator.CreateInstance(type7);//无参数的构造函数 { //【4】获取私有方法 //1,通过方法名来调用方法 //MethodInfo methodInfo = type6.GetMethod("Test4");//私有方法,直接给一个方法名还是不行的 MethodInfo methodInfo = type6.GetMethod("Test4",BindingFlags.Instance|BindingFlags.NonPublic);//获取私有方法需要,参数2:备注,一个说明,指定是一个实例,说明是非公开的 //【5】调用带参数的私有方法 methodInfo.Invoke(oReflection7, new object[]{"json"}); }
4,使用反射调用泛型方法(普通类里面的泛型方法调用)
泛型类和泛型方法的示例代码:
namespace Ant.DB.SQLServer { /// <summary> /// 泛型类 /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="W"></typeparam> /// <typeparam name="S"></typeparam> public class GenericClass<T,W,S> { /// <summary> /// 泛型方法 /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="W"></typeparam> /// <typeparam name="S"></typeparam> /// <param name="t"></param> /// <param name="w"></param> /// <param name="s"></param> public void Test<T,W,S>(T t, W w, S s) { Console.WriteLine($"第一个类型是={t.GetType().Name},第二个类型是={w.GetType().Name},第三个类型是={s.GetType().Name},"); } } /// <summary> /// 普通的类 /// </summary> public class GenericMethod { /// <summary> /// 泛型方法 /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="W"></typeparam> /// <typeparam name="S"></typeparam> /// <param name="t"></param> /// <param name="w"></param> /// <param name="s"></param> public void Test<T,W,S>(T t, W w, S s) { Console.WriteLine($"第一个类型是={t.GetType().Name},第二个类型是={w.GetType().Name},第三个类型是={s.GetType().Name},"); } } }
Console.WriteLine("---------------------------UseReflection 使用反射调用泛型方法(普通类里面的泛型方法调用)-------------------------"); //【1】加载DLL文件 Assembly assembly8 = Assembly.LoadFrom("Ant.DB.SQLServer.dll"); //【2】DLL文件中有很多类型,获取类型(要完整的类型名称) Type type8 = assembly8.GetType("Ant.DB.SQLServer.GenericMethod");//需要 命名空间.类型名称 //【3】创建对象 object oReflection8 = Activator.CreateInstance(type8);//实例化类型 //【4】通过方法名找到方法 MethodInfo methodInfo8 = type8.GetMethod("Test"); //【5】确定方法的参数类型和个数 var methodGeneric = methodInfo8.MakeGenericMethod(new Type[] { typeof(int),typeof(string),typeof(DateTime)}); //【6】调用方法 methodGeneric.Invoke(oReflection8, new object[] {123456, "jason", DateTime.Now});
5,使用反射调用泛型方法(泛型类里面的泛型方法调用)
Console.WriteLine("---------------------------UseReflection 使用反射调用泛型方法(泛型类里面的泛型方法调用)-------------------------"); //【1】加载DLL文件 Assembly assembly9 = Assembly.LoadFrom("Ant.DB.SQLServer.dll"); //【2】DLL文件中有很多类型,获取类型(要完整的类型名称) //Type type9 = assembly9.GetType("Ant.DB.SQLServer.GenericClass");//需要 命名空间.类型名称,这个普通的方法不能获取泛型类型的 Type type9 = assembly9.GetType("Ant.DB.SQLServer.GenericClass`3");//注意:泛型类需要: 反单引号+参数个数 //【3】确定泛型方法的参数类型 Type typeNew9 = type9.MakeGenericType(new Type[] {typeof(int), typeof(string), typeof(DateTime)}); //【4】创建对象 //object oReflection9 = Activator.CreateInstance(type9);//实例化类型 object oReflection9 = Activator.CreateInstance(typeNew9);//实例化类型,需要用新的这个typeNew9 //【5】通过方法名找到方法 MethodInfo methodInfo9 = typeNew9.GetMethod("Test");//需要用新的这个typeNew9 //【6】确定方法的参数类型和个数 var methodGeneric9 = methodInfo9.MakeGenericMethod(new Type[] { typeof(int), typeof(string), typeof(DateTime) }); //【7】调用方法 methodGeneric9.Invoke(oReflection9, new object[] { 123456, "jason", DateTime.Now });
六,使用反射操作字段和属性等成员
要操作的Studnet类的成员
namespace Ant.DB.SQLServer { public class Student { public int Id { get; set; } public string StudentName { get; set; } public string StudentAddress { get; set; } public int age; public void Test() { } } }
Console.WriteLine("---------------------------UseReflection 使用反射操作字段和属性等成员-------------------------"); Student student = new Student() { Id = 1, StudentAddress = "杭州", StudentName = "jason" }; //【1】加载DLL文件 Assembly assembly10 = Assembly.LoadFrom("Ant.DB.SQLServer.dll"); //【2】DLL文件中有很多类型,获取类型(要完整的类型名称) Type type10 = assembly10.GetType("Ant.DB.SQLServer.Student"); //需要 命名空间.类型名称,这个普通的方法不能获取泛型类型的 //【3】创建对象 object oReflection10 = Activator.CreateInstance(type10); //实例化类型 //方式一:获取和设置属性 foreach (var prop in type10.GetProperties()) { Console.WriteLine($"类型:{prop.PropertyType},属性名称:{prop.Name},值:{prop.GetValue(student)}");//注意,这个student是上面的new出来的那个 Console.WriteLine("---------------------------------------"); if (prop.Name.Equals("Id")) { prop.SetValue(student, 2); } if (prop.Name.Equals("StudentAddress")) { prop.SetValue(student, "杭州2"); } if (prop.Name.Equals("StudentName")) { prop.SetValue(student, "jason2"); } Console.WriteLine($"类型:{prop.PropertyType},属性名称:{prop.Name},值:{prop.GetValue(student)}"); } //方式二:获取和设置属性 MemberInfo[] memberInfos=type10.GetMembers();//所有的成员信息,包括属性,字段,方法 PropertyInfo[] propertyInfos = type10.GetProperties();//查找所有的属性 PropertyInfo propertyInfo = type10.GetProperty("Id");//根据名称找到属性
结果:
7,反射调用方法的案例
【7.1】带返回值的
https://blog.csdn.net/ftell/article/details/81745908?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_antiscanv2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_antiscanv2&utm_relevant_index=2
public class MyClass { public string func1() { return "func1"; } public string func2() { return "func2"; } public string func3() { return "func3"; } public string func4() { return "func4"; } public void callFunc(string funcName) { MethodInfo method = GetType().GetMethod(funcName); Func<string> func = (Func<string>)Delegate.CreateDelegate(typeof(Func<string>), this, method); Console.Write(func() + " "); } }
【7.2】带参数的,不带返回值的
public void SetOut_0() { btnCh8_Click(null, null); } public void SetOut_1() { btnCh9_Click(null, null); } public void SetOut_2() { btnCh10_Click(null, null); } public void SetOut_3() { btnCh11_Click(null, null); } public void SetOut_4() { btnCh12_Click(null, null); } public void SetOut_5() { btnCh13_Click(null, null); } public void SetOut_6() { btnCh14_Click(null, null); } public void SetOut(string methodName) { MethodInfo method = GetType().GetMethod(methodName); method.Invoke(this, null); }