有關程序及其類型的數據被稱爲元數據,保存在程序的程序集前端
一個運行的程序查看自己的元數據或者其餘程序的元數據的行爲叫反射程序員
一遍下來啥都沒整明白?沒事,咱只是慣例行事,先放定義。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就行。
何爲依賴注入呢?說的直白點,就是統一實例化對象,把他們都放在一個公共的容器裏,誰要用就拿給誰。