ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

C# 反射 Reflection

2022-02-07 16:01:42  阅读:246  来源: 互联网

标签:反射 Assembly Reflection C# public Person Type ReflectionStudy personType


参考资料:

C#反射机制 - 知乎 (zhihu.com)

一、基本概念

.Net的应用程序由几个部分:‘程序集(Assembly)’、‘模块(Module)’、‘类型(class)’组成,而反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组成部分的相关信息。

 

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

装配件是.Net应用程序执行的最小单位,编译出来的.dll、.exe都是装配件。

 

Module——了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。


Type——可以获得对象的类型信息,此信息包含对象的所有要素:方法、构造器、属性等等,通过Type类可以得到这些要素的信息,并且调用之。

 

ConstructorInfo——了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等


MethodInfo——包含方法的信息,通过这个类可以得到方法的名称、参数、返回值等,并且可以调用之。


EventInfo——了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。


PropertyInfo——了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。


ParameterInfo——了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。

 

.NET中的重要机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类、结构、委托、接口和枚举等)的成员和成员的信息。有了反射,即可对每一个类型了如指掌。另外我还可以直接创建对象,即使这个对象的类型在编译时还不知道。

 

重点:

System.Type类:System.Type 类对于反射起着核心的作用。但它是一个抽象的基类,Type有与每种数据类型对应的派生类,我们使用这个派生类的对象的方法、字段、属性来查找有关该类型的所有信息。获取给定类型的Type引用有3种常用方式:

//2.1、使用C# typeof运算符,是支持强类型的, 前提是项目必须引用反射类所在的程序集
Type personType1 = typeof(Person);
//2.2 使用对象GetType方法
Person p1 = new Person();
Type personType2 = p1.GetType();
//2.3调用Type类的静态方法GetType(),Type.GetType()是非强类型,如果参数typeName表示的目标类型不在当前程序集中,那么会返回nul
Type personType3 = Type.GetType("ReflectionStudy.Model.Person");
//此时会返回null,正确的做法是加载程序集,通过2.4的方式去获取

//2.4通过程序集类的Assembly的静态方法GetType()
Assembly assembly2 = Assembly.Load("ReflectionStudy.Model");
Type personType4 = assembly2.GetType("ReflectionStudy.Model.Person");

Type的属性及含义:

 

 

 Type的方法:

二、实际应用

创建一个实体类库ReflectionStudy.Model,创建两个实体类

namespace ReflectionStudy.Model
{
//公司 internal class Company { public string Name { get; set; } public string Description { get; set; } public string Owner { get; set; } }
//人员 public class Person { public string Name { get; set; } public int Age { get; set; } public int Id { get; set; } //不带set\get的为字段,带set/get的为属性 public string Introduction; //公开方法 public void IntroduceMyself(string word) { Console.WriteLine(word); } //私有方法 private void TakeShower() { Console.WriteLine("洗澡"); }

          //带参数的公共方法
          public void WriteString(string s, int i)
          {
               Console.WriteLine("WriteString:" + s + i.ToString());
          }
         //带一个参数的静态方法
         public static void StaticWriteString(string s)
         {
            Console.WriteLine("StaticWriteString:" + s);
         }

    }
}

创建一个控制台程序ReflectionStudy,引用程序集,在program.cs当中创建对应的方法

1、读取程序集

public static void  GetProgramAssembly()
        {
            //读取已引用的程序集
            // 引用的程序会编译后,生成dll文件存放在bin目录
            //D:\repos2022\ReflectionStudy\bin\Debug\net5.0\ReflectionStudy.Model.dll
            //获取ReflectionStudy.Model.dll中的实体类
            //三种方式等价:
            Assembly assembly1 = Assembly.LoadFrom("ReflectionStudy.Model.dll");
            Assembly assembly2 = Assembly.Load("ReflectionStudy.Model");
            Assembly assembly3 = Assembly.LoadFile(@"D:\repos2022\ReflectionStudy\bin\Debug\net5.0\ReflectionStudy.Model.dll");
            //遍历程序集中的所有class
            foreach (var type in assembly3.GetTypes())
           {
               Console.WriteLine($"名称:{type.Name},属性:{type.BaseType.Name}");
           }

        }

运行结果:

//1、读取程序集
{
                GetProgramAssembly();
                //结果打印:
                //名称:Person,属性:Object
                //名称:Company,属性:Object
}

2、根据类型创建实体类, Activator.CreateInstance(Type,。。。),第一个参数为需要创建对象的类型,后面的为调用构造函数的参数,下面例子为调用无参构造函数。

public static void GetEntityInfo()
        {
            //1、加载程序集
            Assembly assembly = Assembly.Load("ReflectionStudy.Model");
            //2、获取类型,注意带上完整的命名空间,三种方式
            Type personType = assembly.GetType("ReflectionStudy.Model.Person");

            //3、根据类型创建实体类
            object? person = Activator.CreateInstance(personType);
            //4.1、遍历属性
            foreach (var property in personType.GetProperties())
            {
                Console.WriteLine($"类:{personType.Name},属性:{property.Name}");
            }
            //4.2、遍历类的方法
            foreach (var method in personType.GetMethods())
            {
                Console.WriteLine($"类:{personType.Name},方法:{method.Name}");
            }
            //4.3遍历字段
            foreach (var field in personType.GetFields())
            {
                Console.WriteLine($"类:{personType.Name},字段:{field.Name}");
            }

        }

运行结果:

//2、利用反射获取类的相关信息(字段、属性、方法)
            {
                GetEntityInfo();
                //结果打印
                //类:Person,属性:Name
                //类:Person,属性:Age
                //类:Person,属性:Id
                //类:Person,方法:get_Name
                //类:Person,方法:set_Name
                //类:Person,方法:get_Age
                //类:Person,方法:set_Age
                //类:Person,方法:get_Id
                //类:Person,方法:set_Id
                //类:Person,方法:IntroduceMyself
                //类:Person,方法:GetType
                //类:Person,方法:ToString
                //类:Person,方法:Equals
                //类:Person,方法:GetHashCode
                //类:Person,字段:Introduction
            }

3、利用反射给类里的字段赋值、执行类里的方法

//设置、获取属性;执行方法
        public static void GetOrSetProperties()
        {
            //1、加载程序集
            Assembly assembly = Assembly.Load("ReflectionStudy.Model");
            //2、获取类型,注意带上完整的命名空间,三种方式
            Type personType = assembly.GetType("ReflectionStudy.Model.Person");
            //3、根据类型创建实体类
            object? person = Activator.CreateInstance(personType);
            //3、获取属性
            PropertyInfo ageInfo = personType.GetProperty("Age");
            PropertyInfo nameInfo = personType.GetProperty("Name");
            //4、属性赋值
            nameInfo.SetValue(person,"张三");
            ageInfo.SetValue(person,22);

            //打印
            Console.WriteLine($"姓名:{nameInfo.GetValue(person)},年龄:{ageInfo.GetValue(person)}");

            //5、获取方法
            ////BindingFlags类型枚举,BindingFlags.NonPublic | BindingFlags.Instance 组合才能获取到private私有方法,不带此参数默认为public的方法
            MethodInfo m1 = personType.GetMethod("TakeShower", BindingFlags.NonPublic | BindingFlags.Instance);
            MethodInfo m2 = personType.GetMethod("StaticWriteString");
            MethodInfo m3 = personType.GetMethod("WriteString");
            
            //6、执行方法
            // public object? Invoke(object? obj, object?[]? parameters);
            //6.1不带参
            m1.Invoke(person,null);
            //6.2 带一个个参
            m2.Invoke(person, new string[]{"哈哈哈"});
            //6.3 带多个参
            string test = "爱在";
            int i = 520;
            Object[] parametors = new Object[] {test, i};
            m3.Invoke(person, parametors);
        }

执行结果:

//3、设置或获取属性的值、执行方法
            {
                GetOrSetProperties();
                //执行结果:
                //姓名:张三,年龄:22
                //洗澡
                //StaticWriteString:哈哈哈
                //WriteString:爱在520
            }

4、可利用反射+简单工厂+配置文件实现不同数据库的灵活切换和配置,见附件代码

博客后台 - 博客园 (cnblogs.com)

 

标签:反射,Assembly,Reflection,C#,public,Person,Type,ReflectionStudy,personType
来源: https://www.cnblogs.com/summerZoo/p/15868155.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有