百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

C#核心-反射揭秘1(c#反射的作用)

liebian365 2024-11-17 13:18 21 浏览 0 评论

大家都知道反射吧,但是我想大部分业务开发者都很少会用反射,反正我写业务代码的时候很少用到。反射大多用于框架而非业务层面,我们不想只会写业务代码吧?面试造火箭入职打螺丝是现实,前提是你面试能造火箭,所以不管从利益角度或者对写程序的热爱角度我们都要攻克反射等一系列写框架代码所需要的技术,这也是我写文章的目的。

既然我说反射大多用于框架层面,那么我就先从几个用到反射的框架来讲解一下,让大家有一个认识。我先说一下依赖注入(DI,后面统称DI)中反射的应用。

DI是IOC(控制反转)思想的实现之一,作用是让框架帮你创建对象,而非你自己去实例化一个对象。如下图。


请看图1,类里面定义了一些接口字段,在构造函数形参都是接口,然后在构造函数里面进行赋值。这样我们的类方法就可以用这些接口字段使用对应的服务了。为什么可以这么做,不应该是创建实例化对象赋值给这些接口字段才能使用相对应的服务吗?请看下图红色框


像图3这样,创建实例化对象赋值给对应接口字段,或者这些字段直接定义成类实例变量,这样我们才好理解,也是我们的惯用写法。首先我们需要知道一个设计原则,就是里氏替换原则,这个原则说的是派生类的实例可以赋值给基类或者基接口。这个原则有什么好处呢,我们可以直接看图1来说明好处,好处就是图1里面没有看到实现类,或者说只依赖了接口,依赖接口的好处就是减少了耦合,如果按照图3这种实现方式,首先需要实例化,如果有100个类要用到图3红框的类,如果这么写,意味着如果要改这个类名我得修改这100个类,这样不符合开闭原则(对扩展开放,对修改封闭),这里就是对这100个类修改不封闭了,因为改一个类名我得修改这100类。

这里你是否想到了一些设计模式,比如简单工厂模式,抽象工厂模式。工厂模式也是解决这个问题的,意思就是一个服务类在业务应用很多的地方要用接口或者基类代替,这样注入的是一个接口和基类,而我要修改类,比如修改类名,或者换一个实现类,我只需要在工厂里面修改即可,不需要修改很多使用它的程序,因为工厂只有一个,使用它的程序可能成千上万。

依赖接口或者依赖基类也是有依赖的,比如我修改接口方法名,或者修改接口名也是得修改所有使用它的代码,但是要比依赖类来的更好,毕竟我们注入的是接口或者基类,是比较不容易变动的东西。为什么要参考这些开发原则,就是因为这些原则帮助我们写出低耦合,可拓展的代码,最终让程序更稳定,活得更久。

我们回到图1的代码,回到我们的主题反射,图1为什么可以这么做,是因为我们图1

GoodsController这个类最终的实例化是类似下面这样的:

new GoodsController(new 接口派生类实例化对象,new 接口派生类实例化对象,...)

实例化过程构造函数里面传的都是实例化对象,所以导致图1这样的写法是可以实现的,因为里氏替换原则。

然后上面的实例化过程在DI里面会使用反射的方式实现,不然还是会依赖具体派生类,我们上面反复说到,只要依赖具体派生类,使用的多了,就不符合开闭原则,真的要像上面这样实现,那么我们图1就没有意义。

请看图2,显示了autofac这个DI的使用方式,目的是在程序初始化的时候收集接口和派生类的关系,把这个关系保存到内存中,然后使用的过程中用反射进行操作。这样说比较抽象,我先甩出一个反射的方式实例化对象的方式,请看下面代码。

var obj = Activator.CreateInstance(Type type);

这句代码就是通过反射实例化一个无参构造函数的对象,参数是Type,也就是一个派生类的类型引用,通过typeof(类)就可以获取。而这个type我们在刚才说的DI初始化收集的接口和派生类关系中的派生类,这样我们就可以通过接口拿到对应派生类的Type,然后使用上面这个反射实例化代码拿到实例了。伪代码就变成了这样。

new GoodsController(接口=>拿到派生类Type=>Activator.CreateInstance(Type),...)

这样实例化对象了,而这个过程是框架做的,而不需要你手动写,当然new GoodsController这个过程也可以通过Activator.CreateInstance替换。所以DI框架要实现这么一个过程,它首先需要收集接口和派生类的关系,然后使用的时候需要告诉DI框架你需要调用什么类什么方法,你可能告诉DI框架是一个字符串,比如"GoodsController/GetGoods"意思就是GoodsController这个类的GetGoods方法,然后DI框架就会使用反射实例化GoodsConroller对象,然后调用GetGoods方法。这个就像我们开发api接口一样,前端访问接口传过来的路由是

"https://xxx/控制层/方法" ,我们路由的处理就是通过反射的方式创建控制层实例对象,然后调用它的方法。所以我们可以按照图1这样写代码了,前面实例化过程都由DI框架去做。

上面DI这个例子大部分都是理论没有实际代码,因为毕竟本篇重点不是DI而是反射。

我再举一个简单的例子,好用且可以说清楚代码的例子。

请看下图。






我们后端写一个进货单状态枚举,如果前端需要使用这个进货单状态进行数据查询,那么一般的方式是前后端分别写死,要加一个状态,那么前后端都要修改,这样有一个坏处就是如果新增了一个进货单状态,后端要改,前端也要改,如果沟通不及时,或者前后端更新时间不能一致的时候就会有问题。那么最好的方式就是后端开放一个接口,让前端查询最新的进货单状态列表,这样前后端就可以保持一致了。

图6图7就是通过反射的方式解析枚举的数据然后组装对象集合返回到前端的。

string GetDescription<T>(this int val) where T:struct

这个扩展方法就是拿到某一个枚举值对应的描述值,

里面核心的代码是

typeof(T).GetTypeInfo().DeclaredFields.FirstOrDefault(w => String.Compare(w.Name, enumValue.ToString(), true) == 0);

这个就是反射的用法之一,通过类的Type就可以拿到这个类的所有成员,方法,事件,字段,属性等等,而且也可以调用方法,赋值获取字段属性等等。

IEnumerable<SelectListItem> BuildSelectItemsForEnum<T>(int selectedValue = 0) where T : struct

这个方法就是拿到所有的枚举值,然后调用GetDescription方法拿到枚举值对应的描述值,然后组装成我们想要的数据。

这个例子非常轻量级,但是非常好用,也是通过反射技术实现的。

上面两个例子,我们可以看到,通过一个类型的Type,我们可以创建它的实例化对象,可以查询字段,属性,方法,事件等成员,而且还可以调用他们。这个调用过程都不知道具体类型的,具体类型是我们传给他们的。

今日头条文章有字数限制,请接着看

C#核心-反射揭秘2

相关推荐

4万多吨豪华游轮遇险 竟是因为这个原因……

(观察者网讯)4.7万吨豪华游轮搁浅,竟是因为油量太低?据观察者网此前报道,挪威游轮“维京天空”号上周六(23日)在挪威近海发生引擎故障搁浅。船上载有1300多人,其中28人受伤住院。经过数天的调...

“菜鸟黑客”必用兵器之“渗透测试篇二”

"菜鸟黑客"必用兵器之"渗透测试篇二"上篇文章主要针对伙伴们对"渗透测试"应该如何学习?"渗透测试"的基本流程?本篇文章继续上次的分享,接着介绍一下黑客们常用的渗透测试工具有哪些?以及用实验环境让大家...

科幻春晚丨《震动羽翼说“Hello”》两万年星间飞行,探测器对地球的最终告白

作者|藤井太洋译者|祝力新【编者按】2021年科幻春晚的最后一篇小说,来自大家喜爱的日本科幻作家藤井太洋。小说将视角放在一颗太空探测器上,延续了他一贯的浪漫风格。...

麦子陪你做作业(二):KEGG通路数据库的正确打开姿势

作者:麦子KEGG是通路数据库中最庞大的,涵盖基因组网络信息,主要注释基因的功能和调控关系。当我们选到了合适的候选分子,单变量研究也已做完,接着研究机制的时便可使用到它。你需要了解你的分子目前已有哪些...

知存科技王绍迪:突破存储墙瓶颈,详解存算一体架构优势

智东西(公众号:zhidxcom)编辑|韦世玮智东西6月5日消息,近日,在落幕不久的GTIC2021嵌入式AI创新峰会上,知存科技CEO王绍迪博士以《存算一体AI芯片:AIoT设备的算力新选择》...

每日新闻播报(September 14)_每日新闻播报英文

AnOscarstatuestandscoveredwithplasticduringpreparationsleadinguptothe87thAcademyAward...

香港新巴城巴开放实时到站数据 供科技界研发使用

中新网3月22日电据香港《明报》报道,香港特区政府致力推动智慧城市,鼓励公私营机构开放数据,以便科技界研发使用。香港运输署21日与新巴及城巴(两巴)公司签署谅解备忘录,两巴将于2019年第3季度,开...

5款不容错过的APP: Red Bull Alert,Flipagram,WifiMapper

本周有不少非常出色的app推出,鸵鸟电台做了一个小合集。亮相本周榜单的有WifiMapper's安卓版的app,其中包含了RedBull的一款新型闹钟,还有一款可爱的怪物主题益智游戏。一起来看看我...

Qt动画效果展示_qt显示图片

今天在这篇博文中,主要实践Qt动画,做一个实例来讲解Qt动画使用,其界面如下图所示(由于没有录制为gif动画图片,所以请各位下载查看效果):该程序使用应用程序单窗口,主窗口继承于QMainWindow...

如何从0到1设计实现一门自己的脚本语言

作者:dong...

三年级语文上册 仿写句子 需要的直接下载打印吧

描写秋天的好句好段1.秋天来了,山野变成了美丽的图画。苹果露出红红的脸庞,梨树挂起金黄的灯笼,高粱举起了燃烧的火把。大雁在天空一会儿写“人”字,一会儿写“一”字。2.花园里,菊花争奇斗艳,红的似火,粉...

C++|那些一看就很简洁、优雅、经典的小代码段

目录0等概率随机洗牌:1大小写转换2字符串复制...

二年级上册语文必考句子仿写,家长打印,孩子照着练

二年级上册语文必考句子仿写,家长打印,孩子照着练。具体如下:...

一年级语文上 句子专项练习(可打印)

...

亲自上阵!C++ 大佬深度“剧透”:C++26 将如何在代码生成上对抗 Rust?

...

取消回复欢迎 发表评论: