Fork me on GitHub

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

posted @ 2019-07-09 16:29  都一样*  阅读(480)  评论(0编辑  收藏  举报