C# 反射概念及应用场景

元数据(MetaData)和反射(reflection):
一般情况下我们的程序都在处理数据的读、写、操作和展示。但是有些程序操作的数据不是数字、文本、图片,而是程序和程序类型本身的信息。
①元数据是包含程序以及类型信息的数据,它保存在程序的程序集当中。
②程序在运行的时候,可以查看其他程序集或者其本身的元数据。这个行为就是反射。.Net的应用程序由几个部分:‘程序集(Assembly)’、‘模块(Module)’、‘类型(class)’组成,而反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组成部分的相关信息,例如:
       Assembly类可以获得正在运行的装配件信息,也可以动态的加载装配件,以及在装配件中查找类型信息,并创建该类型的实例。
       Type类可以获得对象的类型信息,此信息包含对象的所有要素:方法、构造器、属性等等,通过Type类可以得到这些要素的信息,并且调用之。
       MethodInfo包含方法的信息,通过这个类可以得到方法的名称、参数、返回值等,并且可以调用之。
诸如此类,还有FieldInfo、EventInfo等等,这些类都包含在System.Reflection命名空间下。

Type类:
BCL声明了一个Type类型(它是抽象类),用来包含类型的特性。使用这个类的对象能让我们获取程序使用的类型的信息。
由于Type是抽象类,所以它不能被实例化。而是在运行时,CLR创建从Type(RuntimeType)派生的类型的实例。当我们要访问这些实例的时候,CLR不会返回派生类的引用而是返回Type基类的引用。
关于Type有如下重要的点:
①对于程序每一个需要用到的类型,CLR会穿件一个包含这个类型信息的Type类型的对象(真实的是上面说的派生的类型的实例)。
②程序中用到的每一个类型都会关联到独立的Type类的对两个象。

计算机执行过程:

对于计算机来讲,它只认识01010101之类的二进制代码,人类写的高级语言(如C#、JAVA等)计算机是没法识别的,所以需要将高级语言转化为01让计算机可以识别的二进制编码,中间是有一个过程的。就拿C#来讲,VS编译器会将编写好的代码进行编译,编译后会生成exe/dll文件,.Net Core里面已经不生成exe了,都是dll。dll和exe还需要CLR/JIT的即时编译成字节码,才能最终被计算机执行。有伙伴就会问为什么要编译2次呢,先编译到dll,再编译到字节码01呢,为什么不能一次性编译成字节码呢?因为我们写的是C#语言,但是真实运行的机器有很多种,可能是32位,也可能是64位,操作系统可能是windows、linux、unix等,不同的计算机不同的操作系统识别字节码的可能是不一样的,但是从高级语言编译成exe/dll这一步是一样的。所以只要在不同运行环境的计算机上安装对应的不同的CLR/JIT,就可以运行我们同一个exe/dll了。这里就大概讲下这样一个过程,后面会有章节详细讲解程序如何被计算机执行的。现在我们先关注编译生成的exe/dll,它包含2部分,分别是中间语言IL和源数据元数据metadata。IL里面包含我们写的大量的代码,比如说方法、实体类等。元数据metadata不是我们写的代码,它是编译器在编译的时候生成的描述,它可能是把命名空间、类名、属性名记录了一下,包括特性,反射可以动态的调取对象中的方法,这就是反射的好处。

反射使用:

获取对象类型的几种方法:

方法一:GetType方法,object类型包含了一个GetType方法,它可以用来返回事例的Type对象引用。由于所有的类都是继承自object类型,所以所有的类都可以调用GetType来获得Type类型对象的引用。
方法二:还可以通过typeof()方法来获取一个类型的Type对象引用。
方法三:根据程序集Assembly来获取程序集内的类型。

namespace Test
{ 
    class BaseClass
    {
        public int BaseField = 0;
    }
    publice class test
    {
        private void main()
        {
            BaseClass baseClass = new BaseClass();
            var type1 = baseClass.GetType();
            var type2 = typeof(BaseClass);
            var type3 = Assembly.GetExecutingAssembly().GetType("Test.BaseClass");
        }
    }
}

创建类型的构造函数:

Activator.CreateInstance (Type);//无参数
Activator.CreateInstance (Type, Object[]);//带参数
Activator.CreateInstance 泛型方法 ();//创建类型的一个实例,该类型由指定的泛型类型参数指定

获取程序集及所有类类型:

//运行目录下dll文件
Assembly dll = Assembly.LoadFrom("HelloWord.dll");// Assembly.LoadFrom("HelloWord");
var types=dll.GetTypes();

调用程序集类方法及委托调用:

namespace Webtest
{
    public class ReflectTest
    {       
        public string WriteString(string s,int i)
        {
             return "欢迎您," + s + "---" + i; ;
         }
   }
}

namespace Test
{
    public class TestClass
    {       
        delegate string TestDelegate(string value, int value1);
        private void Main()
        {
            Assembly dll = Assembly.LoadFrom("HelloWord.dll");      // Assembly.LoadFrom("HelloWord");
            object obj = dll.CreateInstance("Webtest.ReflectTest"); //获得程序集类实例
            Type t = dll.GetType("Webtest.ReflectTest");            //获得程序集类类型
            MethodInfo mi = t.GetMethod("WriteString");             //显示类具体的方法
            object[] aa = { "使用的是带有参数的非静态方法", 2 };
            //直接调用
            string r=  (string)mi.Invoke(obj, aa);                  //调用类实例方法委托

            //委托调用
            TestDelegate method = (TestDelegate)Delegate.CreateDelegate(typeof(TestDelegate), obj, "WriteString");
            string result=method("str1", 2);
        }
   }
}

动态设置、获取类(Project)的属性值:

namespace Test
{ 
    class BaseClass
    {
           public int BaseField { get; set; }
    }
    publice class test
    {
        private void main()
        {
            BaseClass baseClass = new BaseClass();
            Type classtype = baseClass.GetType();
            object classInstance = Activator.CreateInstance(classtype);
            PropertyInfo id = classtype.GetProperty("BaseField");//获取属性信息
            id.SetValue(classInstance, 1);//设置属性
            var projectId = id.GetValue(classInstance);//读取属性
        }
    }
}

利用反射将类转结构体:


namespace Test
{ 
    class BaseClass
    {
           public int BaseField { get; set; }
    }
    struct BaseStruct
    {
        public int BaseField;
    }

    publice class test
    {
        private void main()
        {
            BaseClass baseClass = new BaseClass();
            Type classtype = baseClass.GetType();
            object classInstance = Activator.CreateInstance(classtype);
            PropertyInfo id = classtype.GetProperty("BaseField");
            id.SetValue(classInstance, 1);

            BaseStruct baseStruct = new BaseStruct();
            object strcut= Activator.CreateInstance(baseStruct.GetType());
            //方式一
            FieldInfo[] fieldInfos = typeof(BaseStruct).GetFields();
            foreach (FieldInfo StruValue in fieldInfos)
            {
                PropertyInfo classname = classtype.GetProperty(StruValue.Name);
                var value = classname.GetValue(classInstance);
                StruValue.SetValue(strcut, value);
            }
            //方式二
            foreach (System.Reflection.PropertyInfo p in baseClass.GetType().GetProperties())
            {
                PropertyInfo classname = classtype.GetProperty(p.Name);
                var value = classname.GetValue(classInstance);
                FieldInfo stuctname = baseStruct.GetType().GetField(p.Name);
                stuctname.SetValue(strcut, value);
            }
        }
    }
}

参考:https://www.cnblogs.com/dcz2015/p/11058193.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

无熵~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值