有关程序及其类型的数据被称为元数据,保存在程序的程序集前端
一个运行的程序查看自己的元数据或者其余程序的元数据的行为叫反射程序员
一遍下来啥都没整明白?没事,咱只是惯例行事,先放定义。c#
先抛开反射这些乱七八糟的东西,咱们来想一想看:当你打开了游戏充值页面想要变强的时候,界面是否是有不少个选项?支付宝付款,微信支付,银行卡支付,应有尽有,反正只要你想掏钱,咱们必定不会让爷您这钱花不出去。微信
做为一个爱思考的程序员,在卡上数字减小的时候,你已经在面无表情的思考这个支付页面背后的逻辑了。那怎么作呢?最简单的固然是写 if
else
语句,他是第几个radio你就调用哪一个进行付款。ide
这样作确实没什么问题,但会不会麻烦了一点?银行支付那么多个银行,每增长一个就写一句if
吗?这就彻底是体力活了,有没有办法能够省事一点呢?最好我说用支付宝付款就用支付宝付款,你别说,还真能够。微信支付
终于轮到咱们的主角反射登场了!BCL声明了一个Type
抽象类,使用Type
类的对象能够获取到程序使用的类型信息。咱们能够用GetType
或者typeof
运算符来获取Type
对象。ui
Type类成员spa
Name 返回类型名字
Namespace 返回包含类型声明的命名空间
Assembly 返回声明类型的程序集
GetFields 返回类型的字段列表
GetProperties 返回类型的属性列表
GetMethods 返回类型的方法列表code
咱们从前端界面得知了要调用的类名,如今咱们根据它的名字来建立实例并调用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就行。
何为依赖注入呢?说的直白点,就是统一实例化对象,把他们都放在一个公共的容器里,谁要用就拿给谁。