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