C# 反射机制详解

本文详细介绍了C#中的反射机制,包括基础概念如命名空间与装配件的关系,反射的用途和使用,如获取程序集、类型信息、动态创建对象等。通过反射,可以在运行时获取类型信息,动态创建对象,操作类成员,适用于插件扩展等场景。然而,反射会带来性能损失,因此应谨慎使用。文章还提到了动态类型dynamic作为反射的一种优化选择。
摘要由CSDN通过智能技术生成

0. 基础概念

0.1 什么是反射

Reflection,中文翻译为反射。
这是.Net中获取运行时类型信息的方式。

官方定义:
审查元数据并收集关于它的类型信息的能力。
元数据(编译以后的最基本数据单元)
就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等。

.Net的应用程序的结构由以下几个部分组成:

  • 程序集(Assembly)

  • 模块(Module)

  • 类型(class)

在这里插入图片描述

而反射的层次模型也类似上述结构:

  • 程序集反射
  • 类型反射
  • 类型成员反射

在这里插入图片描述

而反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组成部分的相关信息。

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

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

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

诸如此类,还有FieldInfo、EventInfo等等,这些类都包含在System.Reflection命名空间下。

0.2 命名空间与装配件的关系

  • 命名空间类似与Java的包,但又不完全等同
    因为Java的包必须按照目录结构来放置,命名空间则不需要。
  • 装配件是.Net应用程序执行的最小单位,编译出来的.dll、.exe都是装配件。

装配件和命名空间的关系不是一一对应,也不互相包含
一个装配件里面可以有多个命名空间,一个命名空间也可以在多个装配件中存在。

例如:

装配件A:

namespace  N1
{
      public  class  AC1  {…}
      public  class  AC2  {…}
}
namespace  N2
{
      public  class  AC3  {…}
      public  class  AC4{…}
}

装配件B:

namespace  N1
{
      public  class  BC1  {…}
      public  class  BC2  {…}
}
namespace  N2
{
      public  class  BC3  {…}
      public  class  BC4{…}
}

这两个装配件中都有N1和N2两个命名空间,而且各声明了两个类,这样是完全可以的

然后我们在一个应用程序中引用装配件A
那么在这个应用程序中,我们能看到N1下面的类为AC1和AC2,N2下面的类为AC3和AC4。

接着我们去掉对A的引用,加上对B的引用
那么我们在这个应用程序下能看到的N1下面的类变成了BC1和BC2,N2下面也一样。

如果我们同时引用这两个装配件
那么N1下面我们就能看到四个类:AC1、AC2、BC1和BC2。

装配件是一个类型 “居住” 的地方,那么在一个程序中要使用一个类,就必须告诉编译器这个类住在哪儿,编译器才能找到它,也就是说必须引用该装配件。

那么如果在编写程序的时候,也许不确定这个类在哪里,仅仅只是知道它的名称,就不能使用了吗?
答案是可以,这就是反射了,就是在程序运行的时候提供该类型的地址,而去找到它。

0.3 使用反射的情景

举个例子来说明:
很多软件开发者喜欢在自己的软件中留下一些接口,其他人可以编写一些插件来扩充软件的功能。

比如我有一个媒体播放器,我希望以后可以很方便的扩展识别的格式,那么我声明一个接口:

public  interface  IMediaFormat
{
   string  Extension  {get;}
   Decoder  GetDecoder();
}

这个接口中包含一个Extension属性,这个属性返回支持的扩展名。
另一个方法返回一个解码器的对象(这里我假设了一个Decoder的类,这个类提供把文件流解码的功能,扩展插件可以派生之),通过解码器对象我就可以解释文件流。

那么我规定所有的解码插件都必须派生一个解码器,并且实现这个接口,在GetDecoder方法中返回解码器对象,并且将其类型的名称配置到我的配置文件里面。

这样的话,我就不需要在开发播放器的时侯知道将来扩展的格式的类型,只需要从配置文件中获取现在所有解码器的类型名称,而动态的创建媒体格式的对象,将其转换为IMediaFormat接口来使用。

这就是一个反射的典型应用。

1. 反射的用途

反射的作用:

  • 它允许在运行时查看属性(attribute)信息。

  • 它允许审查集合中的各种类型,以及实例化这些类型。

  • 它允许延迟绑定的方法和属性(property)。

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值