明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

VB.net是怎么做到的(一、二)

[摘要]VB.net是怎樣做到的(一)VB.net能夠?qū)崿F(xiàn)很多C#不能做到的功能,如When語句、Optional參數(shù)、局部Static變量、對(duì)象實(shí)例訪問靜態(tài)方法、Handles綁定事件、On Error處...
VB.net是怎樣做到的(一)

VB.net能夠?qū)崿F(xiàn)很多C#不能做到的功能,如When語句、Optional參數(shù)、局部Static變量、對(duì)象實(shí)例訪問靜態(tài)方法、Handles綁定事件、On Error處理異常、Object直接后期綁定等等。VB和C#同屬.net的語言,編譯出來的是同樣的CIL,但為什么VB支持很多有趣的特性呢。我們一起來探究一下。

首先是局部Static變量。VB支持用Static關(guān)鍵字聲明局部變量,這樣在過程結(jié)束的時(shí)候可以保持變量的數(shù)值:

Public Sub Test1()

Static i As Integer

i += 1 '實(shí)現(xiàn)一個(gè)過程調(diào)用計(jì)數(shù)器

End Sub

我們實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的過程計(jì)數(shù)器。每調(diào)用一次Test,計(jì)數(shù)器的數(shù)值就增加1。其實(shí)還有很多情況我們希望保持變量的數(shù)值。而C#的static是不能用在過程內(nèi)部的。因此要實(shí)現(xiàn)過程計(jì)數(shù)器,我們必須聲明一個(gè)類級(jí)別的變量。這樣做明顯不如VB好。因?yàn)闊o法防止其他過程修改計(jì)數(shù)器變量。這就和對(duì)象封裝一個(gè)道理,本來應(yīng)該是一個(gè)方法的局部變量,現(xiàn)在我要被迫把它獨(dú)立出來,顯然是不好的設(shè)計(jì)。那么VB是怎么生成局部靜態(tài)變量的呢?將上述代碼返匯編,我們可以清楚地看到在VB生成的CIL中,i不是作為局部變量,而是作為類的Field出現(xiàn)的:

.field private specialname int32 $STATIC$Test1$2001$i

也就是說,i被改名作為一個(gè)類的字段,但被冠以specialname。在代碼中試圖訪問$STATIC$Test1$2001$i是不可能的,因?yàn)樗皇且粋(gè)有效的標(biāo)識(shí)符。但是在IL中,將這個(gè)變量加一的代碼卻與一般的類字段完全一樣,是通過ldfld加載的。我覺得這個(gè)方法十分聰明,把靜態(tài)變量變成生命周期一樣的類字段,但是又由編譯器來控制訪問的權(quán)限,讓它成為一個(gè)局部變量。同時(shí)也解釋了VB為什么要用兩個(gè)不同的關(guān)鍵字來聲明靜態(tài)變量——Static和Shared

VB.net是怎樣做到的(二)

VB.net支持一項(xiàng)很有意思的功能——MyClass。大部分人使用MyClass可能僅限于調(diào)用本類其他構(gòu)造函數(shù)時(shí)。其實(shí)MyClass可以產(chǎn)生一些很獨(dú)特的用法。MyClass永遠(yuǎn)按類的成員為不可重寫的狀態(tài)進(jìn)行調(diào)用,即當(dāng)類的方法被重寫后,用MyClass仍能得到自身的版本。下面這個(gè)例子和VB幫助中所舉的例子非常相似

Public Class MyClassBase
Protected Overridable Sub Greeting()
Console.WriteLine("Hello form Base")
End Sub

Public Sub UseMe()
Me.Greeting()
End Sub

Public Sub UseMyClass()
MyClass.Greeting()
End Sub
End Class

Public Class MyClassSub
Inherits MyClassBase

Protected Overrides Sub Greeting()
Console.WriteLine("Hello form Sub")
End Sub
End Class

我們用一段代碼來測(cè)試:

Dim o As MyClassBase = New MyClassSub()

o.UseMe()
o.UseMyClass()

結(jié)果是UseMe執(zhí)行了子類的版本,而UseMyClass還是執(zhí)行了基類本身的版本,盡管這是一個(gè)虛擬方法。觀其IL,可以看到其簡(jiǎn)單的實(shí)現(xiàn)原理:

Me用的調(diào)用指令是callvirt

IL_0001: callvirt instance void App1.MyClassBase::Greeting()

而MyClass調(diào)用的是call

IL_0001: call instance void App1.MyClassBase::Greeting()

奇怪的是,如此簡(jiǎn)單的一個(gè)功能,我竟然無法用C#實(shí)現(xiàn),C#怎樣也不允許我按非虛函數(shù)的方式調(diào)用一個(gè)虛函數(shù)。C++可以用類名::方法名的方式訪問自身版本的函數(shù),但C#的類名只能用來訪問靜態(tài)的成員。這真是C#一個(gè)奇怪的缺陷。