反射简介
反射
有关程序及其类型的数据被称为元数据,保存在程序的程序集
一个运行的程序查看本身的元数据或者其他程序的元数据的行为叫反射
一遍下来啥都没整明白?没事,咱只是惯例行事,先放定义。
动态创建类并调用其方法
先抛开反射这些乱七八糟的东西,我们来想想看:当你打开了游戏充值页面想要变强的时候,界面是不是有很多个选项?支付宝付款,微信支付,银行卡支付,应有尽有,反正只要你想掏钱,我们一定不会让爷您这钱花不出去。
作为一个爱思考的程序员,在卡上数字减少的时候,你已经在面无表情的思考这个支付页面背后的逻辑了。那怎么做呢?最简单的当然是写 if
else
语句,他是第几个radio你就调用哪个进行付款。
这样做确实没什么问题,但会不会麻烦了一点?银行支付那么多个银行,每增加一个就写一句if
吗?这就完全是体力活了,有没有办法可以省事一点呢?最好我说用支付宝付款就用支付宝付款,你别说,还真可以。
终于轮到我们的主角反射登场了!bcl声明了一个type
抽象类,使用type
类的对象可以获取到程序使用的类型信息。我们可以用gettype
或者typeof
运算符来获取type
对象。
type类成员
name 返回类型名字
namespace 返回包含类型声明的命名空间
assembly 返回声明类型的程序集
getfields 返回类型的字段列表
getproperties 返回类型的属性列表
getmethods 返回类型的方法列表
我们从前端界面得知了要调用的类名,现在我们根据它的名字来创建实例并调用pay方法进行支付。
using system; using system.io; using system.reflection; namespace sample { class zhifubao { public void pay(string money) { console.writeline($"使用支付宝支付{money}元"); } } class weixing { public void pay(string money) { console.writeline($"使用微信支付{money}元"); } } class program { static void main(string[] args) { //获取命名空间 string namespace = path.getfilenamewithoutextension(system.reflection.assembly.getexecutingassembly().location); //要调用的类名 string classname = "zhifubao"; type type = type.gettype(namespace + "." + classname); //生成实例 object obj = activator.createinstance(type); //获取pay方法并调用 methodinfo method = type.getmethod("pay"); method.invoke(obj,new object[]{ "666" }); //调用微信支付 classname = "weixing"; type = type.gettype(namespace + "." + classname); obj = activator.createinstance(type); method = type.getmethod("pay"); method.invoke(obj, new object[] { "666" }); /* * 程序输出结果为: * 使用支付宝支付666元 * 使用微信支付666元 */ } } }
怎么样?代码是不是一下就少了很多,其实反射的功能远不止这些。
依赖注入
我们还可以用别人封装好的反射来实现依赖注入。驾驶员驾驶车辆,拥有私有属性ivehicle
,car和tank类都实现了ivehicle接口。
class program { static void main(string[] args) { //注册服务 var sc = new servicecollection(); sc.addscoped(typeof(ivehicle), typeof(car)); sc.addscoped<driver>(); var sp = sc.buildserviceprovider(); var driver = sp.getservice<driver>(); driver.drive(); } }
如果我们有一天要开坦克了,那么也只需要把typeof(car)
换成tank就行。
何为依赖注入呢?说的直白点,就是统一实例化对象,把他们都放在一个公共的容器里,谁要用就拿给谁。