
變量(variable)表示存儲(chǔ)的位置。每個(gè)變量都有類型,類型決定變量保存的值的類型。C# 是一門類型安全的語言,C# 編譯器會(huì)確保變量中保存一個(gè)適合類型的值。變量的值可通過賦值或通過使用 ++ 與 -- 操作符改變。
變量必須在獲得(obtained)前被明確賦值(definitely assigned)(第五章第三節(jié))。
如以下部分所述,變量要么初始已賦值(initially assigned),要么初始未賦值(initially unassigned)。初始已賦值的變量有非常明確(well-defined)的初始值,且視己為被明確賦值(definitely assigned)的。初始未賦值的變量沒有初始值(initial value)。對于初始未賦值變量來說,為了在某個(gè)位置能明確賦值,必須在通往該位置的每一個(gè)可能執(zhí)行到的分支對該變量賦值。
C# 定義了七種變量:靜態(tài)變量(static variables)、實(shí)例變量(instance variables)、數(shù)組元素(array elements)、值參數(shù)(value parameters)、引用參數(shù)(reference parameters)、輸出參數(shù)(output parameters)和局部變量(local variables)。本節(jié)將對上述類型逐一介紹。
下例中
class A{ public static int x; int y; void F(int[] v, int a, ref int b, out int c) { int i = 1; c = a + b++; }}x 是靜態(tài)變量,y 是實(shí)例變量,v[0] 是數(shù)組元素,a 是值參數(shù),b 是引用參數(shù),c 是輸出參數(shù),i 是局部變量。
以靜態(tài)修飾符 static 聲明的字段被稱為靜態(tài)變量(static variable)。靜態(tài)變量在其所在類型的靜態(tài)構(gòu)造函數(shù)(第十章第十二節(jié))執(zhí)行之前便已存在,當(dāng)其所相關(guān)的應(yīng)用域(application domain)退出時(shí)不再存在。
靜態(tài)變量的初始值是其類型的默認(rèn)值(第五章第二節(jié))。
為了明確賦值檢查,靜態(tài)變量被視為初始已賦值的。
不以靜態(tài)修飾符 static 聲明的字段叫做實(shí)例變量(instance variable)。
類的實(shí)例變量在該類被創(chuàng)建實(shí)例時(shí)開始存在,當(dāng)所有對該實(shí)例的引用都終止、實(shí)例析構(gòu)函數(shù)(若有)執(zhí)行過后,該類的實(shí)例變量不再存在。
類實(shí)例變量的初始值是該變量類型的默認(rèn)值(第五章第二節(jié))。
為了明確賦值檢查,類的實(shí)例變量被認(rèn)為是初始已賦值的。
結(jié)構(gòu)實(shí)例變量的生命周期與其所屬的結(jié)構(gòu)變量是一樣的。換句話說,當(dāng)結(jié)構(gòu)類型的變量存在或終止時(shí),它的實(shí)例變量也隨之存在或消失。
結(jié)構(gòu)的實(shí)例變量的初始賦值狀態(tài)與其所在的結(jié)構(gòu)變量一樣。換句話說,當(dāng)結(jié)構(gòu)變量被視為初始化已賦值時(shí),其實(shí)例變量也被視為初始化已賦值;當(dāng)結(jié)構(gòu)變量被視為初始化未賦值時(shí),其實(shí)例變量也為初始化未賦值。
當(dāng)數(shù)組實(shí)例被創(chuàng)建時(shí),數(shù)組元素開始存在;當(dāng)沒有任何引用指向該數(shù)組實(shí)例時(shí),數(shù)組元素消失。
數(shù)組的每一個(gè)元素的初始值均為該數(shù)組元素類型的默認(rèn)值(第五章第二節(jié))。
為了明確賦值檢查,數(shù)組元素被認(rèn)為是初始已賦值的。
不使用 ref 或 out 修飾符的參數(shù)聲明叫做值參數(shù)(value parameter)。
值形參再調(diào)用該參數(shù)所屬的函數(shù)成員(方法、實(shí)例構(gòu)造函數(shù)、訪問器或操作符)或匿名函數(shù)時(shí)開始存在,并由調(diào)用者提供的實(shí)參的值初始化。一般來說,值形參的存在直到函數(shù)成員或匿名函數(shù)返回結(jié)果為止。然而,如果值形參如果被匿名函數(shù)(第七章第十五節(jié))捕獲(capture),則其生命周期將被至少延長到由該匿名函數(shù)創(chuàng)建的委托或表達(dá)式樹可被垃圾回收為止。
為了明確賦值檢查,值參數(shù)被認(rèn)為是初始已賦值的。
使用 ref 修飾符的參數(shù)聲明叫做引用參數(shù)(reference parameter)。
引用形參不會(huì)創(chuàng)建新的本地存儲(chǔ)位置。相反,引用形參表示其存儲(chǔ)位置與函數(shù)成員或匿名函數(shù)調(diào)用所給定的實(shí)參的存儲(chǔ)位置是一樣的。因此,引用形參的值總是與基礎(chǔ)變量相同。
下面的明確賦值規(guī)則適用于引用形參。注意,對輸出形參(output parameters)規(guī)則與第五章第 1.6 節(jié)中所描述的規(guī)則不同。
在結(jié)構(gòu)類型的實(shí)例方法或?qū)嵗L問器中,this 關(guān)鍵字的行為與該結(jié)構(gòu)類型所引用的形參相同(第七章第 6.7 節(jié))。
使用 out 修飾符的參數(shù)聲明叫做輸出參數(shù)(output parameter)。
輸出形參不會(huì)創(chuàng)建新的本地存儲(chǔ)位置。相反,輸出形參表示與函數(shù)成員或委托調(diào)用所給定的存儲(chǔ)位置是一樣的。因此,輸出形參的值總是與基礎(chǔ)變量相同。
下面的明確賦值規(guī)則適用于輸出形參。注意,對引用形參(reference parameters)規(guī)則與第五章第 1.5 節(jié)中所描述的規(guī)則不同。
在結(jié)構(gòu)類型的實(shí)例方法中,this 關(guān)鍵字的行為與該結(jié)構(gòu)類型所輸出的形參相同(第七章第 6.7 節(jié))。
局部變量(local variable)由 local-variable-declaration 所聲明,可出現(xiàn)在 block、for-statement、switch-statement 或 using-statement 內(nèi);或由 foreach-statement 或 specific-catch-clause 的 try-statement 聲明。
局部變量的生命周期是程序執(zhí)行期間的一部分,在此期間定會(huì)為其保留存儲(chǔ)。這個(gè)生命周期至少從進(jìn)入相關(guān)的 block、for-statement、switch-statement、using-statement、foreach-statement 或 specific-catch-clause 開始,到該 block、for-statement、switch-statement、using-statement、foreach-statement 或 specific-catch-clause 以任何方式結(jié)束為止。(進(jìn)入閉包的 block 或方法調(diào)用會(huì)掛起(suspends)——但不會(huì)結(jié)束——當(dāng)前的 block、for-statement、switch-statement、using-statement、foreach-statement 或 specific-catch-clause。)如果局部變量被匿名函數(shù)(第七章第 15.5.1 節(jié))捕獲,其生命周期至少延長到從該匿名函數(shù)創(chuàng)建的委托或表達(dá)式樹,以及其它引用該捕獲變量的對象可被垃圾回收為止。
如果遞歸地進(jìn)入(entered recursively)父 block、for-statement、switch-statement、using-statement、foreach-statement 或 specific-catch-clause,每次都會(huì)創(chuàng)建該局部變量的新實(shí)例,并重新計(jì)算其 local-variable-initializer(若有)。
由 local-variable-declaration 引入的局部變量不會(huì)自動(dòng)初始化,因此沒有默認(rèn)值。為了明確賦值檢查的目的,由 local-variable-declaration 引入的局部變量被認(rèn)為是初始未賦值(initially unassigned)的。local-variable-declaration 可以包括 local-variable-initializer,在此情況下,位于初始化表達(dá)式(第五章第 3.3.4 節(jié))之后的變量被視作明確賦值的。
由 local-variable-declaration 引入的局部變量的范圍內(nèi),在 local-variable-declarator 文本位置之前引用該局部變量會(huì)導(dǎo)致「編譯時(shí)錯(cuò)誤」。如果局部變量的聲明是隱式的(第八章第 5.1 節(jié)),那么在 local-variable-declarator 內(nèi)引用該變量同樣會(huì)報(bào)錯(cuò)。
由 foreach-statement 或 specific-catch-clause 引入的局部變量在整個(gè)范圍內(nèi)被視作明確賦值的。
局部變量的實(shí)際生命周期是依賴于具體實(shí)現(xiàn)的(implementation-dependent)。比方說,編譯器可能靜態(tài)地(statically)決定某個(gè)塊中的局部變量只用于該塊的一小部分(a small portion of that block)。基于此分析,編譯器生成的代碼可能會(huì)使該變量的存儲(chǔ)生命周期短于其所在的塊。
局部引用變量所引用的存儲(chǔ)(storage)的回收(reclaimed)獨(dú)立于該局部引用變量(第三章第九節(jié))的生命周期
下列分類的變量將自動(dòng)初始化其默認(rèn)值:
變量默認(rèn)值依賴于其變量類型,并由以下規(guī)定確定:
默認(rèn)值初始化是一般是內(nèi)存管理器(memory manager)或垃圾回收器(garbage collector)在分配內(nèi)存給其使用之前,將內(nèi)存的「所有位置零(all-bits-zero)」。基于此,很方便使用「所有位置零」表示空引用(null reference)。
在函數(shù)成員可執(zhí)行代碼中的給定位置,如果編譯器能夠通過特別的靜態(tài)流程分析(particular static flow analysis,第五章第 3.3 節(jié))證明變量已被自動(dòng)初始化(automatically initialized)或至少一次被作為賦值的目標(biāo),那么稱變量已被明確賦值。非正式地來講,明確賦值的規(guī)則如下:
對于以上這些非正式的規(guī)則的正式規(guī)范在第五章第 3.1 節(jié)、第五章第 3.2 節(jié)以及第五章第 3.3 節(jié)中介紹。
對于 struct-type 變量之實(shí)例變量的明確賦值狀態(tài),既可以單獨(dú)跟蹤(tracked individually),也可以整體跟蹤(tracked collectively)。另外除上述規(guī)則外,下列規(guī)則也將應(yīng)用于 struct-type 變量及其實(shí)例變量:
struct-type 變量時(shí),被視作已被明確賦值;struct-type 變量的每個(gè)實(shí)例變量都視作明確賦值時(shí),它也被視作明確賦值。下列上下文是必須明確賦值的:
struct-type 變量且作為成員訪問的左操作數(shù)出現(xiàn)。return 語句或通過執(zhí)行到函數(shù)成員體的尾部并返回),以確保函數(shù)成員不會(huì)在輸出參數(shù)中返回未定義的值(undefined values),因此允許編譯器把將變量作為輸出參數(shù)的函數(shù)成員的調(diào)用視作等價(jià)于對變量的賦值。struct-type 實(shí)例構(gòu)造函數(shù)的 this 變量必須在實(shí)例構(gòu)造函數(shù)所返回的每一個(gè)位置上明確賦值。以下變量分類被歸入初始已賦值(initially assigned):
以下變量分類被歸入初始未賦值(initially unassigned):
this 變量為了確定每個(gè)所用變量是否已明確賦值,編譯器必須使用與本節(jié)所述之一等價(jià)的處理過程。
編譯器會(huì)處理每一個(gè)具有至少一個(gè)初始未賦值變量的函數(shù)成員的主體。對于每一個(gè)初始未賦值的變量 v,編譯器在以下函數(shù)成員內(nèi)節(jié)點(diǎn)確定其明確賦值狀態(tài):
v 的明確賦值狀態(tài)可以是:
v 都已經(jīng)賦值。v 將明確賦值,但當(dāng)其運(yùn)算結(jié)果為 false 時(shí)則不一定。v 將明確賦值,但當(dāng)其運(yùn)算結(jié)果為 true 時(shí)則不一定。下列規(guī)則控制變量 v 在每一個(gè)位置上如何決定明確賦值狀態(tài)的。
在指向某塊(block)語句列表(statement list)中第一句語句(如果語句列表為空(empty)則指向該塊結(jié)束點(diǎn))的控制轉(zhuǎn)移上 v 的明確賦值狀態(tài)與語句、checked 或 unchecked 語句之前的 v 的明確賦值狀態(tài)一致。
對于由表達(dá)式 expr 組成的表達(dá)式語句 stmt:
expr 開頭位置的 v 的明確賦值狀態(tài)與 stmt 開頭處的一致;expr 結(jié)尾處是明確賦值的,那么在 stmt 結(jié)尾點(diǎn)也是明確賦值的,不然相反。stmt 是不帶初始化器的聲明語句,則 v 在 stmt 結(jié)束點(diǎn)與在 stmt 開頭處具有相同的明確賦值狀態(tài);stmt 是一個(gè)帶初始化器的聲明語句,則確定 v 的明確賦值狀態(tài)時(shí)可將之視為語句列表,每個(gè)帶初始化器的聲明對應(yīng)一句賦值語句(按聲明的順序)。對于形如以下的 if 語句 stmt:
if ( expr ) then-stmt else else-stmtexpr 開頭位置的 v 的明確賦值狀態(tài)與 stmt 開頭處一致;expr 結(jié)尾處是明確賦值的,那么在指向 then-stmt 以及任意一個(gè) else-stmt 或 stmt 結(jié)尾點(diǎn)(如果沒有 else 子句)的控制流轉(zhuǎn)移上是明確賦值的;expr 結(jié)尾處的狀態(tài)是「在 true 表達(dá)式之后明確賦值」,那么在指向 then-stmt 的控制流轉(zhuǎn)移上是明確賦值的,但指向 else-stmt 或 stmt 的結(jié)尾點(diǎn)(如果沒有 else 子句)的控制流轉(zhuǎn)移上是未明確賦值的;expr 結(jié)尾點(diǎn)的狀態(tài)是「在 false 表達(dá)式之后明確賦值」,那么在指向 else-stmt 的控制流轉(zhuǎn)移上是明確賦值的,但指向 then-stmt 的控制流轉(zhuǎn)移上是未明確賦值的。位于 stmt 結(jié)束點(diǎn)(當(dāng)且僅當(dāng)在 then-stmt 結(jié)尾點(diǎn)是明確賦值的)上是明確賦值的。then-stmt、else-stmt 或 stmt 結(jié)尾點(diǎn)(如果沒有 else 子句)的控制流轉(zhuǎn)移上的 v 被視作未明確賦值。在帶有控制表達(dá)式 expr 的 switch 語句 stmt:
expr 開始位置的 v 的明確賦值狀態(tài)與位于 stmt 開頭位置的 v 的狀態(tài)是一致的;expr 結(jié)尾處的明確賦值狀態(tài)。對于形如以下的 while 語句 stmt:
while ( expr ) while-bodyexpr 開頭位置的 v 的明確賦值狀態(tài)與 stmt 開頭處的一致;expr 結(jié)尾處是明確賦值的,那么在指向 while-body 的控制流轉(zhuǎn)移上以及在 stmt 結(jié)尾點(diǎn)上的狀態(tài)是明確賦值的;expr 結(jié)尾點(diǎn)的狀態(tài)是「在 true 表達(dá)式之后明確賦值」,那么在指向 while-body 的控制流轉(zhuǎn)移上它是明確賦值的,但在 stmt 結(jié)尾點(diǎn)上是未明確賦值的;expr 結(jié)尾點(diǎn)的狀態(tài)是「在 false 表達(dá)式之后明確賦值」,那么在指向 stmt 結(jié)尾點(diǎn)的控制流轉(zhuǎn)移上它是明確賦值的,單位指向 while-body 的控制流轉(zhuǎn)移上它未明確賦值的。對 do 語句的明確賦值檢查有以下形式:
do do-body while ( expr ) ;stmt 開頭處到 do-body 的控制流轉(zhuǎn)移(control flow transfer)上的 v 的明確賦值狀態(tài)與 stmt 開頭處的一致。expr 開頭處的 v 的明確賦值狀態(tài)與 do-body 結(jié)尾處的一致。expr 結(jié)尾處 v 是明確賦值的,那么在 stmt 結(jié)尾處的控制硫轉(zhuǎn)移上的 v 也是明確賦值的。expr 結(jié)尾處 v 具有「在 false 表達(dá)式之后明確賦值」,那么在 stmt 結(jié)尾處的控制硫轉(zhuǎn)移上的 v 也是明確賦值的。對 for 語句的明確賦值檢查有以下形式:
for ( for-initializer ; for-condition ; for-iterator ) embedded-statement如下面所寫語句一樣:
{ for-initializer ; while ( for-condition ) { embedded-statement ; for-iterator ; }}如果 for-condition 從語句中省略,則當(dāng)評估明確賦值狀態(tài)時(shí),可將上述展開語句中的 for-condition 當(dāng)做 true。
由 break、continue 或 goto 語句導(dǎo)致的控制流轉(zhuǎn)移(control flow transfer)上 v 的明確賦值狀態(tài)與語句開始處 v 的明確賦值狀態(tài)一致。
對于以下形式的語句 stmt:
throw expr ;位于 expr 開頭處 v 的明確賦值狀態(tài)與 stmt 開頭處 v 的狀態(tài)一致。
對于以下形式的語句 stmt:
return expr ;expr 開頭 v 的明確賦值狀態(tài)與 stmt 開頭 v 的狀態(tài)是一致的。expr 之后;try-finally 或 try-catch-finally 的 finally 塊的結(jié)尾處。對于以下形式的語句 stmt:
return ;stmt 之前;return 語句的 try-catch 或 try-catch-finally 的 finally 塊的結(jié)尾處。對于以下形式的語句 stmt:
try try-blockcatch(...) catch-block-1...catch(...) catch-block-ntry-block 開始處的 v 的明確賦值狀態(tài)與 stmt 開頭處一致;catch-block-i 開始處(對于任意 i)的 v 的明確賦值狀態(tài)與 stmt 開頭處一致;try-block 結(jié)尾點(diǎn)和每一個(gè) catch-block-i(i ∈ [1, n])的結(jié)尾點(diǎn)是明確賦值的,則位于 stmt 結(jié)尾點(diǎn)的 v 的明確賦值狀態(tài)是明確賦值的。對于以下形式的 try 語句 stmt:
try try-block finally finally-blocktry-block 開始處的 v 的明確賦值狀態(tài)與 stmt 開頭處一致;finally-block 開始處的 v 的明確賦值狀態(tài)與 stmt 開頭處一致;stmt 結(jié)尾點(diǎn)的 v 的明確賦值狀態(tài)是明確賦值的:try-block 結(jié)束點(diǎn)是明確賦值的;finally-bolck 結(jié)束點(diǎn)是明確賦值的。如果控制流轉(zhuǎn)移(比方說,一個(gè) goto 語句)從 try-block 內(nèi)開始,結(jié)束于 try-block 外,那么如果 v 在 finally-block 的結(jié)束點(diǎn)上明確賦值,在控制流轉(zhuǎn)移上 v 同樣被視作明確賦值的(這不是必要條件,如果 v 在 finally-block 結(jié)束點(diǎn)上是明確賦值的,那么它任被視作明確賦值)。
對于形如下面這段 try-catch-finally 的明確賦值分析
try try-block catch(...) catch-block-1...catch(...) catch-block-nfinally finally-block與將 try-catch 語句閉包于 try-finally 內(nèi)的效果一樣:
try { try try-block catch(...) catch-block-1 ... catch(...) catch-block-n}finally finally-block下例演示了明確賦值在不同 try 語句塊(第八章第十節(jié))中的效果。
class A{ static void F() { int i, j; try { goto LABEL; // i 和 j 都沒有明確賦值 i = 1; // i 明確賦值 } catch { // i 和 j 都沒有明確賦值 i = 3; // i 明確賦值 } finally { // i 和 j 都沒有明確賦值 j = 5; // j 明確賦值 } // i and j 明確賦值 LABEL:; // j 明確賦值 }}對于以下形式的 foreach 語句 stmt:
foreach ( type identifier in expr ) embedded-statementexpr 開頭處的 v 的明確賦值狀態(tài)與 stmt 開頭處的一致;embedded-statement 的控制流轉(zhuǎn)移上的 v 的明確賦值狀態(tài)與 expr 結(jié)尾處的一致。對于以下形式的 using 語句 stmt:
using ( resource-acquisition ) embedded-statementresource-acquisition 開頭處的 v 的明確賦值狀態(tài)與 stmt 開頭處的一致;embedded-statement 的控制流轉(zhuǎn)移上的 v 的明確賦值狀態(tài)與 resource-acquisition 結(jié)尾處的一致。對于以下形式的 lock 語句 stmt:
lock ( expr ) embedded-statementexpr 開頭處的 v 的明確賦值狀態(tài)與 stmt 開頭處的一致;embedded-statement 的控制流轉(zhuǎn)移上的 v 的明確賦值狀態(tài)與 expr 結(jié)尾處的一致。對于以下形式的 yield return 語句 stmt:
yield return expr ;expr 開頭 v 的明確賦值狀態(tài)與 stmt 開頭 v 的狀態(tài)是一致的。stmt 結(jié)尾 v 的明確賦值狀態(tài)與 expr 結(jié)尾 v 的狀態(tài)是一致的。yield break 語句對于明確定義狀態(tài)沒有影響。
以下規(guī)則可應(yīng)用于下諸類型之表達(dá)式:文本(literals,第七章第 6.1 節(jié))、簡單名稱(simple names,第七章第 6.2 節(jié))、成員訪問表達(dá)式(member access expressions,第七章第 6.4 節(jié))、非索引基訪問表達(dá)式(non-indexed base access expressions,第七章第 6.8 節(jié))、typeof 表達(dá)式(typeof expressions,第七章第 6.11 節(jié))以及默認(rèn)值表達(dá)式(default value expressions,第七章第 6.13 節(jié))。
以下規(guī)則可應(yīng)用于下諸類型之表達(dá)式:帶括號(hào)的表達(dá)式(parenthesized expressions,第七章第 6.3 節(jié))、元素訪問表達(dá)式(element access expressions,第七章第 6.6 節(jié))、帶索引的基訪問表達(dá)式(base access expressions with indexing,第七章第 6.8 節(jié))、增量與減量表達(dá)式(increment and decrement expressions,第七章第 6.9 節(jié))、強(qiáng)制轉(zhuǎn)換表達(dá)式(cast expressions,第七章第 7.6 節(jié))、一元 +, -, ~, * 表達(dá)式、二元 +, -, *, /, %, <<, >>, <, <=, >, >=, ==, !=, is, as, &, |, ^ 表達(dá)式(第七章第 8、9、10、11 節(jié))、復(fù)合賦值表達(dá)式(compound assignment expressions, 第七章第 17.2 節(jié))、checked 與 unchecked 表達(dá)式(第七章第 6.12 節(jié))以及數(shù)組與委托創(chuàng)建表達(dá)式(array and delegate creation expressions,第七章第 6.10 節(jié))。
這些表達(dá)式包含一個(gè)或多個(gè)固定順序無條件計(jì)算(unconditionally evaluated in a fixed order)的子表達(dá)式(sub-expressions)。比方說,二元運(yùn)算符 % 先運(yùn)算左邊的值,然后運(yùn)算右邊的。索引操作先計(jì)算索引表達(dá)式(indexed expression),然后從左到右運(yùn)算每個(gè)索引表達(dá)式(index expressions)。對于具有子表達(dá)式 expr1、expr2、……、exprn 的表達(dá)式 expr,按下列順序執(zhí)行:
expr 開頭的狀態(tài)一致;對于以下形式的調(diào)用表達(dá)式(invocation expression)expr:
primary-expression ( arg1 , arg2 , … , argn )或以下形式的對象創(chuàng)建表達(dá)式(object creation expression):
new type ( arg1 , arg2 , … , argn )primary-expression 前 v 的明確賦值狀態(tài)與 expr 前 v 的狀態(tài)一致。primary-expression 后 v 的狀態(tài)是一致的。expr 后 v 的狀態(tài)是一致的。ref 與 out 修飾符。out v)的方式傳入實(shí)參,則 expr 后 v 的狀態(tài)是明確賦值的。否則的話,expr 后 v 的狀態(tài)與 argn 后 v 的狀態(tài)一致。對于形如 w = expr-rhs 的表達(dá)式 expr:
expr-rhs 之前的 v 的明確賦值狀態(tài)與在 expr 前 v 的明確賦值狀態(tài)是一樣的。expr 之后的 v 的明確賦值狀態(tài)為「已被明確扶植」。否則 expr 之后的 v 的明確賦值狀態(tài)與 expr-rhs 之后的 v 的明確賦值狀態(tài)是一樣的。對于形如 expr-first && expr-second 的表達(dá)式 expr:
expr-first 之前的 v 的明確賦值狀態(tài)與在 expr 之前的 v 的明確賦值狀態(tài)是一樣的。expr-first 之后的 v 是明確賦值的或「在 true 表達(dá)式之后明確賦值」,那么在 expr-second 之前的 v 的明確賦值狀態(tài)是明確賦值的。否則,它就不是明確賦值的。expr 之后的 v 的明確賦值狀態(tài)取決于:expr-first 是值為 false 的常量表達(dá)式,則 expr 之后的 v 的明確賦值狀態(tài)與在 expr-first 之后的 v 的狀態(tài)是一樣的。expr-first 之后的 v 的狀態(tài)是明確賦值的,那么 expr 之后的 v 的狀態(tài)也是明確賦值的。expt-second 之后的 v 的狀態(tài)是明確賦值的、并且 expr-first 之后的狀態(tài)是「在 false 表達(dá)式之后明確賦值」,那么 expr 之后的 v 的狀態(tài)是已明確賦值的。expr-second 后的 v 的狀態(tài)是明確賦值或「在 true 表達(dá)式之后明確賦值」,那么 expr 之后 v 的狀態(tài)是「在 true 表達(dá)式之后明確賦值」。expr-first 后 v 的狀態(tài)是「在 false 表達(dá)式之后明確賦值」且 expr-second 后 v 的狀態(tài)是「在 false 表達(dá)式之后明確賦值」,那么 expr 的 v 的狀態(tài)是「在 false 表達(dá)式之后明確賦值」。expr 之后的 v 的狀態(tài)就是未明確賦值了。在下例中
class A{ static void F(int x, int y) { int i; if (x >= 0 && (i = y) >= 0) { // i 明確賦值 } else { // i 沒有明確賦值 } // i 沒有明確賦值 }}變量 i 在 if 語句的其中一個(gè)嵌入語句中被視作是明確賦值的,但在另一個(gè)則不是。在方法 F 的 if 語句中,變量 i 在第一個(gè)嵌入語句中被明確賦值,因?yàn)樵诒磉_(dá)式 (i = y) 執(zhí)行的時(shí)間先于這段嵌入語句的執(zhí)行時(shí)間。相反,變量 i 在第二個(gè)嵌入語句中是未明確賦值的,因?yàn)?x >= 0 為 false 時(shí)的結(jié)果是變量 i 未被賦值。
對于形如 expr-first || expr-second 的表達(dá)式 expr:
expr-first 前 v 的明確賦值狀態(tài)與 expr 前 v 的狀態(tài)是一樣的。expr-first 后 v 的狀態(tài)是明確賦值或「在 false 表達(dá)式之后明確賦值」,那么在 expr-second 前 v 的狀態(tài)是已明確賦值的。否則的話,他就是未明確賦值的。expr 后 v 的明確賦值狀態(tài)取決于:expr-first 是值為 true 的常量表達(dá)式,則 expr 之后的 v 的明確賦值狀態(tài)與在 expr-first 之后的 v 的狀態(tài)是一樣的。expr-first 之后的 v 的狀態(tài)是明確賦值的,那么 expr 之后的 v 的狀態(tài)也是明確賦值的。expt-second 之后的 v 的狀態(tài)是明確賦值的、并且 expr-first 之后的狀態(tài)是「在 true 表達(dá)式之后明確賦值」,那么 expr 之后的 v 的狀態(tài)是已明確賦值的。expr-second 后的 v 的狀態(tài)是明確賦值或「在 false 表達(dá)式之后明確賦值」,那么 expr 之后 v 的狀態(tài)是「在 false 表達(dá)式之后明確賦值」。expr-first 后 v 的狀態(tài)是「在 true 表達(dá)式之后明確賦值」且 expr-second 后 v 的狀態(tài)是「在 true 表達(dá)式之后明確賦值」,那么 expr 的 v 的狀態(tài)是「在 true 表達(dá)式之后明確賦值」。expr 之后的 v 的狀態(tài)就是未明確賦值了。在下例中
class A{ static void G(int x, int y) { int i; if (x >= 0 || (i = y) >= 0) { // i 沒有明確賦值 } else { // i 明確賦值 } // i 沒有明確賦值 }}變量 i 在其中一個(gè)嵌入語句中被視作明確賦值,而在另一個(gè)中則不是。在方法 G 的 if 語句中,變量 i 在第二個(gè)嵌入語句中被視作明確賦值,因?yàn)楸磉_(dá)式 (i = y) 的執(zhí)行將先于這段嵌入語句。與此相反,變量 i 在第一個(gè)嵌入語句中被視作未明確賦值,因?yàn)?x >= 0 可能為 true,那么作為其結(jié)果變量 i 沒有被賦值。
對于形如 ! expr-operand 的表達(dá)式 expr:
expr-operand 前 v 的明確賦值狀態(tài)與 expr 前 v 的狀態(tài)是一樣的。expr 后 v 的明確賦值狀態(tài)取決于:expr-operand 后 v 的狀態(tài)是已明確賦值的,那么 expr 后 v 的狀態(tài)是已明確賦值的expr-operand 后 v 的狀態(tài)是未明確賦值的,那么 expr 后 v 的狀態(tài)是未明確賦值的expr-operand 后 v 的狀態(tài)是「在 false 表達(dá)式后明確賦值」,那么 expr 后 v 的狀態(tài)是「在 true 表達(dá)式后明確賦值」。expr-operand 后 v 的狀態(tài)是「在 true 表達(dá)式后明確賦值」,那么 expr 后 v 的狀態(tài)是「在 false 表達(dá)式后明確賦值」。對于形如 expr-first ?? expr-second 的表達(dá)式 expr:
expr-first 前 v 的明確賦值狀態(tài)與 expr 前 v 的狀態(tài)是一樣的。expr-second 前 v 的明確賦值狀態(tài)與 expr-first 后 v 的狀態(tài)是一樣的。expr 后 v 的明確賦值狀態(tài)取決于:expr-first 是值為 null 的常量表達(dá)式(第七章第十九節(jié)),則 expr 后 v 的狀態(tài)與 expr-second 后 v 的狀態(tài)是一致的。expr 后 v 的狀態(tài)與 expr-first 后 v 的明確賦值狀態(tài)一致。對于形如 expr-cond ? expr-true : expr-false 的表達(dá)式 expr:
expr-cond 前 v 的明確賦值狀態(tài)與 expr 前 v 的狀態(tài)是一樣的。expr-true 前 v 的明確賦值狀態(tài)是已明確賦值的:expr-cond 是值為 false 的常量表達(dá)式。expr-cond 后 v 的狀態(tài)是以明確賦值或「在 true 表達(dá)式后明確賦值」。expr-false 前 v 的明確賦值狀態(tài)是已明確賦值的:expr-cond 是值為 true 的常量表達(dá)式。expr-cond 后 v 的狀態(tài)是以明確賦值或「在 false 表達(dá)式后明確賦值」。(注:原文此處有筆誤)expr 后 v 的明確賦值狀態(tài)取決于:expr-cond 是值為 true 的常量表達(dá)式(第七章第十九節(jié)),則 expr 后 v 的狀態(tài)與 expr-true 后 v 的狀態(tài)一致。expr-cond 是值為 false 的常量表達(dá)式(第七章第十九節(jié)),則 expr 后 v 的狀態(tài)與 expr-false 后 v 的狀態(tài)一致。expr-true 后 v 的狀態(tài)是明確賦值,且 expr-false 后 v 的狀態(tài)也是明確賦值的,則 expr 后 v 的狀態(tài)同樣是明確賦值的。expr 之后的 v 的狀態(tài)就是未明確賦值了。對于具有主體(塊或表達(dá)式)的 Lambda 表達(dá)式(lambda-expression)或匿名方法表達(dá)式(anonymous-method-expression)expr 的主體(body):
body 之前的外部變量 v 的明確賦值狀態(tài)與 expr 之前的 v 的狀態(tài)是一樣的。也就是說,外部變量的明確賦值狀態(tài)繼承自匿名函數(shù)上下文。expr 之后的外部變量 v 的明確賦值狀態(tài)與 expr 之前的 v 的狀態(tài)是一樣的。舉例
delegate bool Filter(int i);void F() { int max; // 錯(cuò)誤,max 沒有明確賦值 Filter f = (int n) => n < max; max = 5; DoWork(f);}由于在匿名函數(shù)被聲明的時(shí)候 max 沒有明確賦值,所以這將產(chǎn)生一個(gè)「編譯時(shí)錯(cuò)誤」。舉個(gè)例子。
delegate void D();void F() { int n; D d = () => { n = 1; }; d(); //錯(cuò)誤,n 沒有明確賦值 Console.WriteLine(n);}由于在匿名函數(shù)之外對匿名函數(shù)內(nèi)部的 n 進(jìn)行明確賦值是沒有效果的,所以這同樣會(huì)產(chǎn)生一個(gè)「編譯時(shí)錯(cuò)誤」。
變量引用(variable-reference)是一個(gè)被歸類到變量(variable)的表達(dá)式(expression)。變量引用表示一個(gè)存儲(chǔ)空間,通過訪問它可以獲取當(dāng)前值、保存新值。
variable-reference: expression在 C 和 C++ 中,變量引用(variable-reference)中稱為 lvalue。
讀寫以下數(shù)據(jù)類型是原子性的(atomic):bool、 char、 byte、 sbyte、 short、 ushort、 uint、 int、 float 以及引用類型。另外,如果枚舉的基礎(chǔ)類型屬于上述列表內(nèi)的,則讀寫該枚舉值也是原子性的。讀寫其它類型,包括 long、 ulong、 double、 decimal 以及用戶自定義的類型時(shí),不能保證一定是原子的。除專門為該墓地設(shè)計(jì)的庫函數(shù)以外,對于增量(increment)或減量(decrement)這種情況,依舊不能保證原子性的讀取、修改與寫入(read-modify-write)。
[1]ARC:Automatic Reference Counting,自動(dòng)引用計(jì)數(shù),是開發(fā)程序時(shí)的一個(gè)編譯級別的特性,用于自動(dòng)內(nèi)存管理。更多請?jiān)L問此處以及此處。
__EOF__
C# Language Specification 5.0 翻譯計(jì)劃
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注