C# 反射
反射:
反射指程序可以访问、检测和修改它本身状态或行为的一种能力。
程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。
您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。
优缺点
优点:
- 1、反射提高了程序的灵活性和扩展性。
- 2、降低耦合性,提高自适应能力。
- 3、它允许程序创建和控制任何类的对象,无需提前硬编码目标类。
缺点:
- 1、性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。
- 2、使用反射会模糊程序内部逻辑;程序员希望在源代码中看到程序的逻辑,反射却绕过了源代码的技术,因而会带来维护的问题,反射代码比相应的直接代码更复杂。
可通过类名、成员的名字类进行对象的实例化、操作类成员
取得Assembly的方法:
Assembly.Load
Assembly.LoadFile
Assembly.LoadFrom
Type对象的Assembly方法
反射的成员:
(1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。
(2)使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
(3)使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。
(4)使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。
(5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。
(6)使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。
(7)使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。
(8)使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。
常用类:
System.Type 类//通过这个类可以访问任何给定数据类型的信息。
Type类的属性:
Name 数据类型名
FullName 数据类型的完全限定名(包括命名空间名)
Namespace 定义数据类型的命名空间名
IsAbstract 指示该类型是否是抽象类型
IsArray 指示该类型是否是数组
IsClass 指示该类型是否是类
IsEnum 指示该类型是否是枚举
IsInterface 指示该类型是否是接口
IsPublic 指示该类型是否是公有的
IsSealed 指示该类型是否是密封类
IsValueType 指示该类型是否是值类型
Type类的方法:
GetConstructor(), GetConstructors():返回ConstructorInfo类型,用于取得该类的构造函数的信息
GetEvent(), GetEvents():返回EventInfo类型,用于取得该类的事件的信息
GetField(), GetFields():返回FieldInfo类型,用于取得该类的字段(成员变量)的信息
GetInterface(), GetInterfaces():返回InterfaceInfo类型,用于取得该类实现的接口的信息
GetMember(), GetMembers():返回MemberInfo类型,用于取得该类的所有成员的信息
GetMethod(), GetMethods():返回MethodInfo类型,用于取得该类的方法的信息
GetProperty(), GetProperties():返回PropertyInfo类型,用于取得该类的属性的信息
可以调用这些成员,其方式是调用Type的InvokeMember()方法,或者调用MethodInfo, PropertyInfo和其他类的Invoke()方法。
System.Reflection.Assembly类//它可以用于访问给定程序集的信息,或者把这个程序集加载到程序中。
先创建一个类
class person//默认partial { public int show(int a) { return a; } public string show(int a, double c) { return a+""+c; } public void showA() { } public static void ShowB() { } private void ShowC() { } private static void ShowD() { } public int a; public static int b; private int c; private static int d; private person(int a, string B) { Console.WriteLine(a + "person类有参函数被调用" + B); } public person() { Console.WriteLine("person类无参函数被调用"); } }
现在开始调用
//通常person p=new person(); //反射: /*BindingFlags: 要访问的方法或字段的权限描述 ,必须要同时具备两个描述 1.要有要访问的成员的访问权限描述 2.要有访问的成员的归属 (静态的是Static 非静态是Instance) */ //通过类名获取一个类型 注意:命名空间 Type T = Type.GetType("ConsoleApp1.person"); //默认会使用public 权限的无参构造方法来实例化 object obj = Activator.CreateInstance(T); //若为true 表示可以匹配任何权限的无参构造函数 object obj1 = Activator.CreateInstance(T, true); //public 权限的 有参构造方法 //object obj2 = Activator.CreateInstance(T, 2, "aaa"); //非public 权限的 有参构造方法 object obj3 = Activator.CreateInstance(T, System.Reflection.BindingFlags.NonPublic | BindingFlags.Instance, null, new Object[] { 1, "BBB" }, null); //通过反射访问类中的字段 //1 public 非静态 a FieldInfo a = T.GetField("a"); a.SetValue(obj, 2); Object aa = a.GetValue(obj); //2访问public 静态 b FieldInfo b = T.GetField("b", BindingFlags.Public | BindingFlags.Static); b.SetValue(null, 3);//要访问的是一个静态成员 访问主体是null object bb = b.GetValue(obj); //3访问public 非静态 c FieldInfo c = T.GetField("c", BindingFlags.NonPublic | BindingFlags.Instance); c.SetValue(obj, 5); object cc = c.GetValue(obj); //4访问private 静态 d FieldInfo d = T.GetField("d", BindingFlags.NonPublic | BindingFlags.Static); d.SetValue(null, 6);//要访问的是一个静态成员 访问主体是null object dd = d.GetValue(obj); //通过反射访问方法 //public 方法A MethodInfo method = T.GetMethod("ShowD", BindingFlags.NonPublic | BindingFlags.Static); method.Invoke(null, null); //public 静态方法 //private 方法C //private 静态方法 //获取有参函数 注意:字符串的大小写 MethodInfo info = T.GetMethod("show", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(int) }, null); //type 数组传 方法的参数列表 object x = info.Invoke(obj, new object[] { 1 }); Console.WriteLine(x);
当然了还有很多时候是要通过exe 或者dll 来操作的
这里新建了一个控制台应用程序 在main 方法中 Console.WriteLine("要输出的内容"); 并且将main 函数中的参数改为无参的
string dllName = "ConsoleApp2";//指定dll文件的名字 程序集的名字 string FullName = "ConsoleApp2.Program";//指定程序及的名字+类的名字 Assembly assembly = Assembly.Load(dllName);//加载程序集 Type type = assembly.GetType(FullName);//从程序集中获取指定对象的类型 object xa = Activator.CreateInstance(type);//创建实例 MethodInfo methodx = type.GetMethod("Main", BindingFlags.NonPublic | BindingFlags.Static); methodx.Invoke(null, null);//这里如果说在ConsoleApp2 中main函数是传入参数要对应 /*static void Main(string[] args) { } */
参考:https://www.bilibili.com/video/av29432157?t=1973 、https://www.runoob.com/csharp/csharp-reflection.html