如何理解C#中的反射Reflection

一、反射(Reflection)

当我们只知道对象外部而不知道内部结构的情况下,通过C#的反射(Reflection)了解对象内部结构。C#中提供的反射(Reflection)机制可动态分析程序集、模块与类型,它不需要New一个对象,便可动态创建使用对象,从而降低代码耦合性。

反射(Reflection)内部实现依赖于元数据。元数据,简单来说,在公共语言运行时CLR中,是一种二进制信息,用来描述数据,数据的属性环境等等的一项数据,那么反射解析数据的内部实现通过元数据实现再合适不过了。

二、举例说明

我先随便写个需要反射的程序集:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StudentClass
{
    public class Student
    {
        public Student()
        {

        }
        public string Name { get; set; }
        public int Age { get; set; }
        public char Gender { get; set; }
        public string IdCard { get; set; }
        public string Address { get; set; }
        private string Mobile { get; set; }
        public void Eat()
        {
            Console.WriteLine("我喜欢吃西瓜!");
        }
        public void Sing()
        {
            Console.WriteLine("我喜欢唱歌!");
        }
        public int Calculate(int a, int b)
        {
            return a + b;
        }
        private string PrivateMethod()
        {
            return "我是一个私有方法";
        }
    }
}

我们来看一下看一下程序集、模块、类等信息:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace ReflectionInvoke
{
    class Program
    {
        static void Main(string[] args)
        {
            //获取程序集信息
            Assembly assembly = Assembly.LoadFile(@"E:\StudentClass\bin\Debug\StudentClass.dll");
            Console.WriteLine("程序集名字:"+assembly.FullName);
            Console.WriteLine("程序集位置:"+assembly.Location);
            Console.WriteLine("运行程序集需要的额CLR版本:"+assembly.ImageRuntimeVersion);
            Console.WriteLine("====================================================");
            //获取模块信息
            Module[] modules = assembly.GetModules();
            foreach (Module item in modules)
            {
                Console.WriteLine("模块名称:"+item.Name);
                Console.WriteLine("模块版本ID"+item.ModuleVersionId);
            }
            Console.WriteLine("======================================================");
            //获取类,通过模块和程序集都可以
            Type[] types = assembly.GetTypes();
            foreach (Type item in types)
            {
                Console.WriteLine("类型的名称:"+item.Name);
                Console.WriteLine("类型的完全命名:"+item.FullName);
                Console.WriteLine("类型的类别:"+item.Attributes);
                Console.WriteLine("类型的GUID:"+item.GUID);
                Console.WriteLine("=====================================================");
            }


            //获取主要类Student的成员信息等
            Type studentType = assembly.GetType("StudentClass.Student");//完全命名
            MemberInfo[] mi = studentType.GetMembers();
            foreach (MemberInfo item in mi)
            {
                Console.WriteLine("成员的名称:"+item.Name);
                Console.WriteLine("成员类别:"+item.MemberType);
            }
            Console.WriteLine("=====================================");

            //获取方法
            BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance;
            MethodInfo[] methodInfo = studentType.GetMethods(flags);
            foreach (MethodInfo item in methodInfo)
            {
                Console.WriteLine("public类型的,不包括基类继承的实例方法:"+item.Name);
            }
            Console.WriteLine("========================================");
            BindingFlags flag = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic;
            MethodInfo[] methods = studentType.GetMethods(flag);
            foreach (MethodInfo item in methods)
            {
                Console.WriteLine("非public类型的,不包括基类继承的实例方法:"+item.Name);
            }
            Console.WriteLine("========================================");

           //获取属性
            BindingFlags flags2 = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance;
            PropertyInfo[] pi = studentType.GetProperties(flags2);
            foreach (PropertyInfo item in pi)
            {
                Console.WriteLine("属性名称:"+item.Name);
            }
        }
    }
}

结果:
在这里插入图片描述
在这里插入图片描述
1、Assembly.Load()以及Assembly.LoadFile():
LoadFile这个方法的参数是程序集的绝对路径,load方法有多个重载,还可以通过流的方式获取程序集,在项目中,主要用来取相对路径,因为很多项目的程序集会被生成在一个文件夹里,此时取相对路径不容易出错。

2、GetTypes和GetType():
很明显第一个获取程序集下所有的类,返回一个数组,第二个要有参数,类名为完全类名:命名空间+类名,用于获取指定的类。

3、Type类下可以获取这个类的所有成员,也可以获取字段属性方法等,有:
ConstructorInfo获取构造函数, FieldInfo获取字段, MethodInfo获取方法,PropertyInfo获取属性,EventInfo获取事件,ParameterInfo获取参数,通过他们的Get方法获取,加s获取所有返回数组,不加s获取具体的。

4、BindFlags:用于对获取的成员的类型加以控制:
BindingFlags.Public公共成员,NonPublic,非公有成员,DeclaredOnly仅仅反射类上声明的成员不包括简单继承的成员。CreateInstance调用构造函数,GetField获取字段值对setField无效。还有很多读者可以F12打开看一下用法以及注释。注意必须指定:BindingFlags.Instance或BindingFlags.Static,主要为了获取返回值,是静态的还是实例的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qqqcheng_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值