反射

    xiaoxiao2023-10-17  160

    反射是.NET中的重要机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类、结构、委托、接口和枚举等)的成员和成员的信息。有了反射,即可对每一个类型了如指掌。另外我还可以直接创建对象,即使这个对象的类型在编译时还不知道 1、什么是反射 Reflection,中文翻译为反射。 这是.Net中获取运行时类型信息的方式,.Net的应用程序由几个部分:‘程序集(Assembly)’、‘模块(Module)’、‘类型(class)’组成,而反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组成部分的相关信息,例如:

    Assembly类可以获得正在运行的装配件信息,也可以动态的加载装配件,以及在装配件中查找类型信息,并创建该类型的实例。

    Type类可以获得对象的类型信息,此信息包含对象的所有要素:方法、构造器、属性等等,通过Type类可以得到这些要素的信息,并且调用之。 MethodInfo包含方法的信息,通过这个类可以得到方法的名称、参数、返回值等,并且可以调用之。 诸如此类,还有FieldInfo、EventInfo等等,这些类都包含在System.Reflection命名空间下。

    01.Type获取方法

    using System; using System.Reflection; using System.Runtime.CompilerServices; using static System.Console; namespace Reflection1 { class Program { static void Main(string[] args) { try { //Person person = new Person(10, "hh"); //Type type = person.GetType(); Type type = typeof(Person); object o = Activator.CreateInstance(type); MethodInfo info = type.GetMethod("Print"); object[] objects = null; info.Invoke(o, objects); } catch (Exception e) { WriteLine(e.Message); } ReadKey(); } } public class Person { public int Age { get; set; } public string Name { get; set; } public Person() { } public Person(int Age, string Name) { this.Age = Age; this.Name = Name; } public void Print() { WriteLine("PrintMethod"); WriteLine(this.Age+":"+this.Name); } } }

    02.type System.Type 类-通过这个类可以访问任何给定数据类型的信息

    class Program { static void Main(string[] args) { //01使用typeof 运算符 Type type1 =typeof(People); //02使用对象GetType()方法 People people =new People(); Type type2 =people.GetType(); //03调用Type类的静态方法GetType() Type type3 =Type.GetType(typeof(People).ToString()); WriteLine(type3.Name); ReadKey(); } } class People { }

    03.Type类型的属性方法字段的调用

    using System; using System.Reflection; using static System.Console; namespace Reflection2 { class Program { static void Main(string[] args) { Type type = typeof(People); //想创建一个方法 方法中传入一个类的名称 然后就能返回一个这个类的实例 object o = Activator.CreateInstance(type); //创建指定类型的实例 //属性 WriteLine("数据类型名:" + type.Name); WriteLine("命名空间名+数据类型名:" + type.FullName); WriteLine("是否是抽象类型:" + type.IsAbstract); WriteLine("是否是数组:" + type.IsArray); WriteLine("是否是类:" + type.IsClass); WriteLine("是否是枚举:" + type.IsEnum); WriteLine("是否是接口:" + type.IsInterface); WriteLine("是否是公有:" + type.IsPublic); WriteLine("是否是是值类型:" + type.IsValueType); //获取类的构造函数信息 ConstructorInfo[] ctors = type.GetConstructors(); //构造函数 ctors[0].Invoke(null); //调用构造函数 FieldInfo[] fieldInfos = type.GetFields(); //类的字段(成员变量)的信息 MethodInfo methodInfo = type.GetMethod("Method1"); //类的方法信息 WriteLine("调用方法:"); methodInfo.Invoke(o, null); PropertyInfo[] propertyInfos = type.GetProperties(); //类的属性的信息 foreach (var propertyInfo in propertyInfos) { WriteLine("属性:" + propertyInfo); } //BindingFlags类型 // 表示查找的时候,需要忽略大小写。 IgnoreCase // 仅查找此特定类型中声明的成员,而不会包括这个类继承得到的成员。DeclaredOnly // 仅查找类型中的实例成员 Instance // 仅查找类型中的静态成员。Static // 仅查找类型中的公共成员。Public // 仅查找类型中的非公共成员(internal protected private)NonPublic // 会查找此特定类型继承树上得到的静态成员。但仅继承公共(public) // 静态成员和受保护(protected)静态成员 // 不包含私有静态成员,也不包含嵌套类型 FlattenHierarchy //调用这些成员 //string:你所要调用的函数名 //BindingFlags:你所要调用的函数的属性,可以组合 //Binder:高级内容,可以先不看 //object:调用该成员函数的实例 //object[]:参数 WriteLine("调用方法"); type.InvokeMember("Method2", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Instance, null,o,null); ReadKey(); } } public class People { public int Age { get; set; } public string Name { get; set; } public People() { WriteLine("无参构造方法"); } public People(int Age, string Name) { this.Age = Age; this.Name = Name; } public void Method1() { WriteLine("Method1"); } public void Method2() { WriteLine("Method2"); } } }

    04.通过程序集加载类 HelloReflection是我们的主要项目,Commond是一个类库项目!我们的目的就是在不引入Commond类库的前提下 在HelloReflection项目中使用Commond中的数据。

    在Commond类库中我们新建了三个类,分别是Person、Student和Teacher类

    using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Commond { public class Person { public int Age { get; set; } public string Name { get; set; } public Person(int age, string name) { this.Age = age; this.Name = name; } public void SayHello() { Console.WriteLine("我是Person类中的函数"); } public void Write() { File.WriteAllText("Person.txt", "张三李四王五赵六田七"); } } } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Commond { internal class Student:Person { public Student(int age, string name) : base(age, name) { } } } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Commond { abstract class Teacher { } }

    要在HelloReflection项目中使用Common程序集,首先需要导入命名空间,并加载程序集文件 Comon程序集文件加载进来后,要使用Common类库中的数据,首先需要获得程序集中的数据类型

    using System; using System.IO; //反射 Assembly需要的命名空间 using System.Reflection; //导入命名空间 using Commond; using static System.Console; namespace HelloReflection { class Program { static void Main(string[] args) { //连接两个路径字符串 string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Commond.dll"); //加载程序集文件 Assembly assembly=Assembly.LoadFile(path); //获得程序集中定义的公共类型 //Type[] types = assembly.GetExportedTypes(); //获得程序集中定义的所有类型,包括公开的和不公开的 Type[] types=assembly.GetTypes(); foreach (Type item in types) { WriteLine("类类型:"+item.Name); } // 获得程序集中指定的类型 Type student=assembly.GetType("Commond.Student"); WriteLine("程序集指定的类型:" + student.Name); ReadKey(); } } }

    获得程序集中的数据类型后,即可以使用这些类型创建类的实例!因为我们无法获得具体的类型,所以在反射中只能动态创建类的实例。 有两种方式,一种是使用程序集对象.CreateInstance()方法创建,另一种是使用Activator.CreateInstance()方法创建,二者返回的都是Object类型的对象。区别是使用程序集.CreateInstance()方法调用系统激活器创建指定类型的实例,只能使用默认的无参构造函数;而如果我们在类库中给指定类自定义了的有参数的构造函数,则需要使用Activator.CreateInstance()来动态创建实例。

    static void Main(string[] args) { //连接两个路径字符串 string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Commond.dll"); //加载程序集文件 Assembly assembly=Assembly.LoadFile(path); //01获得程序集中指定的类型 Type student=assembly.GetType("Commond.Student"); WriteLine("程序集指定的类型:" + student.Name); //02创建类型实例 //从程序集中查找指定类型,然后使用系统激活器创建它的实例(实际上调用类型的默认无参构造函数 object objPerson =assembly.CreateInstance("Commond.Person"); WriteLine("objPerson的类型:"+objPerson.GetType()); // 使用Activator动态创建带有自定义构造函数的类型的实例 object objStudent=Activator.CreateInstance(student, 18, "一休"); WriteLine("objStudent的类型:" + objStudent.GetType()); ReadKey(); }

    创建对象成功后,即可使用对象中的属性、方法、字段、构造函数和事件等 获得数据源中的属性数组

    //04获得数据源中的属性数组 PropertyInfo[] propertyInfos=studentO.GetType().GetProperties(); foreach (var info in propertyInfos) { WriteLine("属性:"+info); } //05获得数据源中的字段 MemberInfo[] memberInfos = studentO.GetType().GetMembers(); foreach (var info in memberInfos) { WriteLine("字段:"+info); } //06获得数据源中的方法 MethodInfo[] methodInfos=studentO.GetType().GetMethods(); foreach (var info in methodInfos) { WriteLine("方法:" + info); } //07 FieldInfo[] fieldInfos=studentO.GetType().GetFields(); foreach (var info in fieldInfos) { WriteLine("字段:" + info); } //08指定对象是否是当前类的实例 WriteLine(student.IsInstanceOfType(studentO));//true //09判断指定类是否是当前类的子类 WriteLine(student.IsSubclassOf(person));//true //10是不是抽象类IsAbstract属性 WriteLine(student.IsAnsiClass);
    最新回复(0)