什么是dynamic類型?
成都創(chuàng)新互聯(lián)公司長期為近1000家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為寬甸企業(yè)提供專業(yè)的成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站,寬甸網(wǎng)站改版等技術(shù)服務(wù)。擁有10年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開發(fā)。
微軟給出的官方文檔中這樣解釋:在通過 dynamic 類型實(shí)現(xiàn)的操作中,該類型的作用是繞過編譯時(shí)類型檢查。 改為在運(yùn)行時(shí)解析這些操作。 dynamic 類型簡化了對 COM API(例如 Office Automation API)、動態(tài) API(例如 IronPython 庫)和 HTML 文檔對象模型 (DOM) 的訪問。在大多數(shù)情況下,dynamic 類型與 object 類型的行為類似。 但是,如果操作包含 dynamic 類型的表達(dá)式,那么不會通過編譯器對該操作進(jìn)行解析或類型檢查。 編譯器將有關(guān)該操作信息打包在一起,之后這些信息會用于在運(yùn)行時(shí)評估操作。 在此過程中,dynamic類型的變量會編譯為 object 類型的變量。 因此,dynamic 類型只在編譯時(shí)存在,在運(yùn)行時(shí)則不存在。
dynamic的出現(xiàn)讓C#具有了弱語言類型的特性。編譯器在編譯的時(shí)候不再對類型進(jìn)行檢查,編譯期默認(rèn)dynamic對象支持你想要的任何特性。
下例中生成的類型是一致的:
dynamic dyn = "Fode"; Object obj = "Fode"; // Rest the mouse pointer over dyn and obj to see their // types at compile time. System.Console.WriteLine(dyn.GetType()); System.Console.WriteLine(obj.GetType());
其輸出結(jié)果都是String類型,可知CLR可以正確的識別出dynamic是哪種類型,在反編譯看看其生成的IL代碼:
IL_0000: nop IL_0001: ldstr "Fode" IL_0006: stloc.0 IL_0007: ldstr "Fode" IL_000c: stloc.1 IL_000d: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey() IL_0012: pop IL_0013: ret
JIT編譯器將dynamic識別為String類型,并將其推算到運(yùn)算棧中(IL代碼中 ldstr(將新對象引用推送到存儲在元數(shù)據(jù)中的字符串文字)、(stloc.*)從評估堆棧的頂部彈出當(dāng)前值,并將其存儲在索引*處的本地變量列表中),不同IL代碼也不所謂,前文只是介紹dynamic這個(gè)類型關(guān)鍵字,只需要你知道他的類型是繞過編譯器就可以,如以下操作,Object類型就會報(bào)編譯的錯(cuò)誤。但是,對于 dyn + 3,不會報(bào)告任何錯(cuò)誤。 在編譯時(shí)不會檢查包含 dyn 的表達(dá)式,原因是 dyn 的類型為 dynamic。
dynamic dyn = "Fode"; Object obj = "Fode"; dyn = dyn + 3; obj = obj + 3; //這句代碼編譯器會報(bào)錯(cuò)
dynamic是Framework 4.0的新特性。dynamic的出現(xiàn)讓C#具有了若語言的特性。編譯器在編譯時(shí)候不再對該類型進(jìn)行檢查,編譯器默認(rèn)dynamic對象支持開發(fā)者想要的任何特征。比如,即使你對 GetStudent()方法返回的對象一無所知,也可以像以下執(zhí)行代碼的調(diào)用,編譯器不會報(bào)錯(cuò):
static void Main(string[] args) { dynamic dyn = GetStudent(); //正確的操作 Console.WriteLine(dyn.Age); Console.WriteLine(dyn.Name); dyn.PrintName(); //錯(cuò)誤的操作 //Console.WriteLine(dyn.Birthday); //該對象沒有包含該屬性 //dyn.PrintAge(); //這行代碼會報(bào)錯(cuò)誤,訪問級別不夠 Console.ReadKey(); } static Student GetStudent() { Student student = new Student(); student.Age = 21; student.Name = "Fode"; return student; } class Student { public String Name { get; set; } public Int32 Age { get; set; } public void PrintName() { Console.WriteLine(this.Name); } private void PrintAge() { Console.WriteLine(this.Age); } }
如果運(yùn)行時(shí)dyn對象不包含指定的特性(屬性、字段、方法等),運(yùn)行時(shí)會拋出一個(gè)運(yùn)行時(shí)的錯(cuò)誤 RuntimeBinderException。
注意:有人可能會將var關(guān)鍵字與dynamic進(jìn)行比較。實(shí)際上,var和dynamic完全是兩回事,兩個(gè)不同的概念。var實(shí)際上是編譯期間拋給我門的“語法糖”,一旦被編譯,編譯器會自動匹配var變量的實(shí)際類型,并用實(shí)際類型來替換給變量的聲明,這看上去就好像我們在編碼的時(shí)候用實(shí)際類型進(jìn)行聲明一樣,優(yōu)點(diǎn)也顯而易見,當(dāng)【賦值方】類型發(fā)生變化時(shí),【實(shí)現(xiàn)方】無需改變其類型,因?yàn)関ar會自動去適配。而dynamic被編譯后,實(shí)際上是一個(gè)Object類型,只不過編譯器會對dynamic類型進(jìn)行特殊處理,讓它在編譯期間不進(jìn)行任何的類型檢查,而是將類型檢查放到了運(yùn)行期。這從VS這個(gè)IDE就能看出,在編輯窗口中,var支持【智能感知】,因?yàn)関s能推斷出var類型的實(shí)際類型;而dynamic聲明的變量卻不支持【智能感知】,因?yàn)閷ζ溥\(yùn)行期的類型一無所知。對dynamic變量使用【智能感知】會提示"此操作將在運(yùn)行時(shí)解析"。
BB了這么久,重點(diǎn)來了,利用好了動態(tài)類型dynamic的這個(gè)特性,可以簡化C#中的反射語法,更高深的優(yōu)化將在以后的博客推出。在dynamic出現(xiàn)之前,我們先用基礎(chǔ)反射獲取一個(gè)類中的方法,并執(zhí)行它:
static void Main() { DynamicObj obj = new DynamicObj(); var fun = obj.GetType().GetMethod(nameof(obj.CallFun)); Int32 result = (Int32)fun.Invoke(obj, new Object[] { "Fode" }); Console.WriteLine(result); Console.ReadKey(); } public class DynamicObj { public Int32 CallFun(String str) { return str.Length; } }
其結(jié)果沒有什么好講的,就是一個(gè)用反射調(diào)用 CallFun() 方法的例子,而用dynamic之后,代碼看上去更簡潔了,并且在可控制的范圍內(nèi)減少了一次拆箱的操作,代碼如下:
dynamic dyn = new DynamicObj(); Int32 result = dyn.CallFun("Fode"); Console.WriteLine(result);
可能我們會對這樣的簡化不以為然,畢竟代碼看起來并沒有減少多少,但是,如果考慮到效率兼優(yōu)美兩個(gè)特性,那么dynamic的優(yōu)勢就顯現(xiàn)出來了。對上面的代碼個(gè)執(zhí)行10000000次,在進(jìn)行分析,如下所示:
CodeTimer.Time("使用dynamic", 10000000, () => { //執(zhí)行里面的代碼10000000次 dynamic dyn = new DynamicObj(); Int32 result = dyn.CallFun("Fode"); }); CodeTimer.Time("使用基礎(chǔ)反射", 10000000, () => { //執(zhí)行里面的代碼10000000次 DynamicObj obj = new DynamicObj(); var fun = obj.GetType().GetMethod(nameof(obj.CallFun)); Int32 result = (Int32)fun.Invoke(obj, new Object[] { "Fode" }); }); Console.ReadKey();
其運(yùn)行結(jié)果如下所示:
從以上結(jié)果看出,使用dynamic使用時(shí)間為481ms,基礎(chǔ)反射使用時(shí)間為3063ms,CPU和時(shí)間上相差了5倍多,測試器 CodeTimer 的代碼隨后會貼出。
總結(jié):
可以看到雖然用dynamic優(yōu)化后的反射跟基礎(chǔ)反射的相比,效率雖然在同一個(gè)數(shù)量級上??墒腔A(chǔ)反射卻沒有dynamic代碼簡潔,因此建議:始終使用dynamic來簡化反射實(shí)現(xiàn)(前提你知道你要是實(shí)現(xiàn)的類型),在往后的隨筆,將會提出用ExpressionTree和Emit技術(shù)深度優(yōu)化反射。
代碼下載:http://xiazai.jb51.net/201812/yuanma/ConsoleApp2_jb51.rar
好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對創(chuàng)新互聯(lián)的支持。
網(wǎng)站標(biāo)題:c#使用dynamic類型優(yōu)化反射的方法
本文鏈接:http://www.rwnh.cn/article12/peopdc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供動態(tài)網(wǎng)站、品牌網(wǎng)站設(shè)計(jì)、響應(yīng)式網(wǎng)站、外貿(mào)建站、品牌網(wǎng)站制作、網(wǎng)站設(shè)計(jì)公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)