運算式Expressions
運算式是一串運算子和運算元。An expression is a sequence of operators and operands. 本章定義語法、運算元和運算子的評估順序,以及運算式的意義。This chapter defines the syntax, order of evaluation of operands and operators, and meaning of expressions.
運算式分類Expression classifications
運算式分類為下列其中一項:An expression is classified as one of the following:
- 值。A value. 每個值都有關聯型別。Every value has an associated type.
- 變數。A variable. 每個變數都有相關聯的類型,也就是變數的宣告型別。Every variable has an associated type, namely the declared type of the variable.
- 命名空間。A namespace. 具有此分類的運算式只能出現在 member_access (成員存取) 的左邊。An expression with this classification can only appear as the left hand side of a member_access (Member access). 在任何其他內容中,分類為命名空間的運算式會導致編譯階段錯誤。In any other context, an expression classified as a namespace causes a compile-time error.
- 類型。A type. 具有此分類的運算式只能出現在 member_access (成員存取) 的左邊,或做為運算子的運算元
as
(as 運算子) 、is
運算子 (is 運算子) 或typeof
運算子 (typeof 運算子) 。An expression with this classification can only appear as the left hand side of a member_access (Member access), or as an operand for theas
operator (The as operator), theis
operator (The is operator), or thetypeof
operator (The typeof operator). 在任何其他內容中,分類為類型的運算式會導致編譯時期錯誤。In any other context, an expression classified as a type causes a compile-time error. - 方法群組,這是成員查閱 (成員查閱) 所產生的一組多載方法。A method group, which is a set of overloaded methods resulting from a member lookup (Member lookup). 方法群組可以有相關聯的實例運算式和關聯的型別引數清單。A method group may have an associated instance expression and an associated type argument list. 叫用實例方法時,評估實例運算式的結果會成為
this
(此存取) 所代表的實例。When an instance method is invoked, the result of evaluating the instance expression becomes the instance represented bythis
(This access). Invocation_expression 的 (調用運算式中允許方法群組) 、 delegate_creation_expression (委派建立運算式) 和做為運算子的左邊,並且可以隱含地轉換為相容的委派類型 (方法群組轉換) 。A method group is permitted in an invocation_expression (Invocation expressions) , a delegate_creation_expression (Delegate creation expressions) and as the left hand side of an is operator, and can be implicitly converted to a compatible delegate type (Method group conversions). 在任何其他內容中,分類為方法群組的運算式會導致編譯時期錯誤。In any other context, an expression classified as a method group causes a compile-time error. - Null 常值。A null literal. 具有此分類的運算式可以隱含地轉換成參考型別或可為 null 的型別。An expression with this classification can be implicitly converted to a reference type or nullable type.
- 匿名函式。An anonymous function. 具有此分類的運算式可以隱含地轉換成相容的委派類型或運算式樹狀架構類型。An expression with this classification can be implicitly converted to a compatible delegate type or expression tree type.
- 屬性存取。A property access. 每個屬性存取都有相關聯的類型,也就是屬性的型別。Every property access has an associated type, namely the type of the property. 此外,屬性存取可能會有相關聯的實例運算式。Furthermore, a property access may have an associated instance expression. 當叫用存取子
get
(set
實例屬性存取的或區塊) 時,評估實例運算式的結果會變成this
(此存取) 所代表的實例。When an accessor (theget
orset
block) of an instance property access is invoked, the result of evaluating the instance expression becomes the instance represented bythis
(This access). - 事件存取。An event access. 每個事件存取都有相關聯的類型,也就是事件的類型。Every event access has an associated type, namely the type of the event. 此外,事件存取可能會有相關聯的實例運算式。Furthermore, an event access may have an associated instance expression. 事件存取可能會顯示為和運算子的左運算元
+=
,-=
(事件指派) 。An event access may appear as the left hand operand of the+=
and-=
operators (Event assignment). 在任何其他內容中,分類為事件存取權的運算式會導致編譯時期錯誤。In any other context, an expression classified as an event access causes a compile-time error. - 索引子存取。An indexer access. 每個索引子存取都有相關聯的類型,也就是索引子的元素類型。Every indexer access has an associated type, namely the element type of the indexer. 此外,索引子存取有相關聯的實例運算式和相關聯的引數清單。Furthermore, an indexer access has an associated instance expression and an associated argument list. 在叫
get
set
用索引子存取 (或區塊) 的存取子時,評估實例運算式的結果會變成this
(此存取) 所表示的實例,而評估引數清單的結果會變成叫用的參數清單。When an accessor (theget
orset
block) of an indexer access is invoked, the result of evaluating the instance expression becomes the instance represented bythis
(This access), and the result of evaluating the argument list becomes the parameter list of the invocation. - 不做任何動作。Nothing. 當運算式是傳回型別為的方法調用時,就會發生這種情況
void
。This occurs when the expression is an invocation of a method with a return type ofvoid
. 分類為 nothing 的運算式只在 statement_expression (運算式語句) 的內容中有效。An expression classified as nothing is only valid in the context of a statement_expression (Expression statements).
運算式的最終結果絕對不是命名空間、類型、方法群組或事件存取。The final result of an expression is never a namespace, type, method group, or event access. 相反地,這些運算式類別是只允許在特定內容中使用的中繼結構。Rather, as noted above, these categories of expressions are intermediate constructs that are only permitted in certain contexts.
屬性存取或索引子存取一律會藉由執行 get 存取 子或 set 存取 子的調用,重新分類為值。A property access or indexer access is always reclassified as a value by performing an invocation of the get accessor or the set accessor. 特定存取子是由屬性或索引子存取的內容所決定:如果存取是指派的目標,則會叫用 set 存取 子,以指派新值給 (簡單指派) 。The particular accessor is determined by the context of the property or indexer access: If the access is the target of an assignment, the set accessor is invoked to assign a new value (Simple assignment). 否則,會叫用 get 存取 子,以取得目前值 () 的運算式值 。Otherwise, the get accessor is invoked to obtain the current value (Values of expressions).
運算式的值Values of expressions
大部分牽涉到運算式的結構最後都需要運算式來表示 值。Most of the constructs that involve an expression ultimately require the expression to denote a value. 在這種情況下,如果實際的運算式表示命名空間、類型、方法群組或 nothing,就會發生編譯時期錯誤。In such cases, if the actual expression denotes a namespace, a type, a method group, or nothing, a compile-time error occurs. 但是,如果運算式表示屬性存取、索引子存取或變數,則會隱含地替代屬性、索引子或變數的值:However, if the expression denotes a property access, an indexer access, or a variable, the value of the property, indexer, or variable is implicitly substituted:
- 變數的值只是目前儲存在變數所識別之儲存位置的值。The value of a variable is simply the value currently stored in the storage location identified by the variable. 變數必須被視為明確指派 (明確 指派) ,才能取得其值,否則就會發生編譯時期錯誤。A variable must be considered definitely assigned (Definite assignment) before its value can be obtained, or otherwise a compile-time error occurs.
- 藉由叫用屬性的 get 存取 子,即可取得屬性存取運算式的值。The value of a property access expression is obtained by invoking the get accessor of the property. 如果屬性沒有 get 存取 子,就會發生編譯階段錯誤。If the property has no get accessor, a compile-time error occurs. 否則,函式成員調用 (動態多載解析) 的編譯時間檢查 ,而且叫用的結果會成為屬性存取運算式的值。Otherwise, a function member invocation (Compile-time checking of dynamic overload resolution) is performed, and the result of the invocation becomes the value of the property access expression.
- 索引子存取運算式的值是透過叫用索引子的 get 存取 子取得。The value of an indexer access expression is obtained by invoking the get accessor of the indexer. 如果索引子沒有 get 存取 子,就會發生編譯時期錯誤。If the indexer has no get accessor, a compile-time error occurs. 否則,會使用與索引子存取運算式相關聯的引數清單來執行動態多載解析) 的函數成員調用 (編譯時間檢查 ,而且叫用的結果會成為索引子存取運算式的值。Otherwise, a function member invocation (Compile-time checking of dynamic overload resolution) is performed with the argument list associated with the indexer access expression, and the result of the invocation becomes the value of the indexer access expression.
靜態和動態繫結Static and Dynamic Binding
根據組成運算式的類型或值 (引數、運算元、接收者) 來判斷作業意義的程式通常稱為系 結。The process of determining the meaning of an operation based on the type or value of constituent expressions (arguments, operands, receivers) is often referred to as binding. 例如,方法呼叫的意義取決於接收者和引數的型別。For instance the meaning of a method call is determined based on the type of the receiver and arguments. 運算子的意義取決於其運算元的型別。The meaning of an operator is determined based on the type of its operands.
在 c # 中,通常會根據其組成運算式的編譯時間類型,在編譯時期決定作業的意義。In C# the meaning of an operation is usually determined at compile-time, based on the compile-time type of its constituent expressions. 同樣地,如果運算式包含錯誤,則編譯器會偵測到錯誤並回報錯誤。Likewise, if an expression contains an error, the error is detected and reported by the compiler. 這種方法稱為 靜態 系結。This approach is known as static binding.
但是,如果運算式是動態運算式 (也就是具有類型 dynamic
) 這表示它所參與的任何系結都應該以其執行時間類型為基礎 (亦即,它在運行) 時間所代表之物件的實際型別,而不是在編譯時期的型別。However, if an expression is a dynamic expression (i.e. has the type dynamic
) this indicates that any binding that it participates in should be based on its run-time type (i.e. the actual type of the object it denotes at run-time) rather than the type it has at compile-time. 因此,這類作業的系結會延後,直到執行程式時執行作業的時間為止。The binding of such an operation is therefore deferred until the time where the operation is to be executed during the running of the program. 這稱為 動態繫結。This is referred to as dynamic binding.
動態繫結作業時,編譯器不會執行任何檢查。When an operation is dynamically bound, little or no checking is performed by the compiler. 相反地,如果執行時間系結失敗,則會在執行時間將錯誤報表為例外狀況。Instead if the run-time binding fails, errors are reported as exceptions at run-time.
C # 中的下列作業受限於系結:The following operations in C# are subject to binding:
- 成員存取:
e.M
Member access:e.M
- 方法調用:
e.M(e1, ..., eN)
Method invocation:e.M(e1, ..., eN)
- 委派調用:
e(e1, ..., eN)
Delegate invocation:e(e1, ..., eN)
- 元素存取:
e[e1, ..., eN]
Element access:e[e1, ..., eN]
- 物件建立:
new C(e1, ..., eN)
Object creation:new C(e1, ..., eN)
- 多載一元運算子:
+
、-
、!
、~
、、、++
--
true
、false
Overloaded unary operators:+
,-
,!
,~
,++
,--
,true
,false
- 多載的二元運算子:
+
、-
、*
、/
、%
、&
、&&
、、|
||
、??
^
<<
>>
==
!=
>
<
>=
、、、、、、、、、、、、、、、、、<=
Overloaded binary operators:+
,-
,*
,/
,%
,&
,&&
,|
,||
,??
,^
,<<
,>>
,==
,!=
,>
,<
,>=
,<=
- 指派運算子:
=
、+=
、-=
、*=
、/=
、%=
、&=
、|=
、^=
、<<=
、>>=
Assignment operators:=
,+=
,-=
,*=
,/=
,%=
,&=
,|=
,^=
,<<=
,>>=
- 隱含和明確轉換Implicit and explicit conversions
如果沒有涉及任何動態運算式,c # 會預設為靜態系結,這表示選取進程中會使用構成運算式的編譯時間類型。When no dynamic expressions are involved, C# defaults to static binding, which means that the compile-time types of constituent expressions are used in the selection process. 不過,當上列作業中的其中一個組成運算式為動態運算式時,作業會改為動態繫結。However, when one of the constituent expressions in the operations listed above is a dynamic expression, the operation is instead dynamically bound.
系結時間Binding-time
靜態系結會在編譯時期發生,而動態繫結則會在執行時間進行。Static binding takes place at compile-time, whereas dynamic binding takes place at run-time. 在下列各節中,系結時間指的是編譯時期或執行時間,視系結的發生時間而 定 。In the following sections, the term binding-time refers to either compile-time or run-time, depending on when the binding takes place.
下列範例說明靜態和動態系結以及系結時間的概念:The following example illustrates the notions of static and dynamic binding and of binding-time:
object o = 5;
dynamic d = 5;
Console.WriteLine(5); // static binding to Console.WriteLine(int)
Console.WriteLine(o); // static binding to Console.WriteLine(object)
Console.WriteLine(d); // dynamic binding to Console.WriteLine(int)
前兩個呼叫會靜態系結: Console.WriteLine
根據其引數的編譯時間類型挑選的多載。The first two calls are statically bound: the overload of Console.WriteLine
is picked based on the compile-time type of their argument. 因此,系結時間是編譯時期。Thus, the binding-time is compile-time.
第三個呼叫是動態系結的: Console.WriteLine
根據其引數的執行時間類型挑選的多載。The third call is dynamically bound: the overload of Console.WriteLine
is picked based on the run-time type of its argument. 發生這種情況是因為引數是動態運算式--其編譯時間類型為 dynamic
。This happens because the argument is a dynamic expression -- its compile-time type is dynamic
. 因此,第三個呼叫的系結時間是執行時間。Thus, the binding-time for the third call is run-time.
動態繫結Dynamic binding
動態繫結的目的是要讓 c # 程式與 動態物件 互動,也就是不遵循 c # 型別系統標準規則的物件。The purpose of dynamic binding is to allow C# programs to interact with dynamic objects, i.e. objects that do not follow the normal rules of the C# type system. 動態物件可以是其他具有不同類型系統之程式設計語言的物件,也可能是以程式設計方式設定的物件,以針對不同的作業來執行自己的系結語法。Dynamic objects may be objects from other programming languages with different types systems, or they may be objects that are programmatically setup to implement their own binding semantics for different operations.
動態物件實作為其本身語義的機制是定義的。The mechanism by which a dynamic object implements its own semantics is implementation defined. 指定的介面--重新執行的已定義--是由動態物件所執行,以通知 c # 執行時間它們具有特殊的語法。A given interface -- again implementation defined -- is implemented by dynamic objects to signal to the C# run-time that they have special semantics. 因此,每當動態物件上的作業動態繫結時,其本身的系結語義(而非本檔中所指定的 c #)都會接管。Thus, whenever operations on a dynamic object are dynamically bound, their own binding semantics, rather than those of C# as specified in this document, take over.
動態繫結的目的是要允許與動態物件的交互操作,但 c # 允許所有物件上的動態系結,不論它們是否為動態。While the purpose of dynamic binding is to allow interoperation with dynamic objects, C# allows dynamic binding on all objects, whether they are dynamic or not. 這可讓您更順暢地整合動態物件,因為這些物件的作業結果可能本身不是動態物件,但在編譯時期仍是程式設計師未知的類型。This allows for a smoother integration of dynamic objects, as the results of operations on them may not themselves be dynamic objects, but are still of a type unknown to the programmer at compile-time. 此外,動態繫結也可協助消除錯誤的反映型程式碼,即使沒有任何相關的物件是動態物件也一樣。Also dynamic binding can help eliminate error-prone reflection-based code even when no objects involved are dynamic objects.
下列各節會在套用動態繫結時,完全描述語言中的每個結構、編譯時間檢查(如果有的話),以及編譯時間結果和運算式分類。The following sections describe for each construct in the language exactly when dynamic binding is applied, what compile time checking -- if any -- is applied, and what the compile-time result and expression classification is.
組成運算式的類型Types of constituent expressions
靜態系結作業時,組成運算式的型別 (例如接收者、引數、索引或運算元) 一律視為該運算式的編譯時間型別。When an operation is statically bound, the type of a constituent expression (e.g. a receiver, an argument, an index or an operand) is always considered to be the compile-time type of that expression.
動態系結作業時,會根據組成運算式的編譯時間類型,以不同的方式決定組成運算式的類型:When an operation is dynamically bound, the type of a constituent expression is determined in different ways depending on the compile-time type of the constituent expression:
- 編譯時間類型的組成運算式會被
dynamic
視為具有運算式在執行時間評估為的實際數值型別。A constituent expression of compile-time typedynamic
is considered to have the type of the actual value that the expression evaluates to at runtime - 編譯時間類型為型別參數的組成運算式,會被視為具有類型參數在執行時間系結的型別。A constituent expression whose compile-time type is a type parameter is considered to have the type which the type parameter is bound to at runtime
- 否則,會將組成運算式視為具有其編譯時間類型。Otherwise the constituent expression is considered to have its compile-time type.
運算子Operators
運算式是從 運算元 _ 和 _運算子*_ 所構成。Expressions are constructed from operands _ and _operators*_. 運算式的運算子會指出要將哪些運算套用到運算元。The operators of an expression indicate which operations to apply to the operands. 運算子範例包括 +
、-
、_
、/
及 new
。Examples of operators include +
, -
, _
, /
, and new
. 運算元範例包括常值、欄位、區域變數及運算式。Examples of operands include literals, fields, local variables, and expressions.
有三種運算子:There are three kinds of operators:
- 一元運算子。Unary operators. 一元運算子採用一個運算元,並使用前置標記法 (例如
--x
) 或後置標記法 (例如x++
) 。The unary operators take one operand and use either prefix notation (such as--x
) or postfix notation (such asx++
). - 二元運算子。Binary operators. 二元運算子採用兩個運算元,且全都使用中置標記法 (例如
x + y
) 。The binary operators take two operands and all use infix notation (such asx + y
). - 三元運算子。Ternary operator. 只有一個三元運算子(
?:
)存在; 它會採用三個運算元,並使用中綴標記法 (c ? x : y
) 。Only one ternary operator,?:
, exists; it takes three operands and uses infix notation (c ? x : y
).
運算式中運算子的評估順序是由運算子的 *優先順序 _ 和 _ 關聯 性 * (運算子優先順序和關聯 性) 所決定。The order of evaluation of operators in an expression is determined by the precedence _ and _ associativity of the operators (Operator precedence and associativity).
運算式中的運算元會由左至右評估。Operands in an expression are evaluated from left to right. 例如,在中, F(i) + G(i++) * H(i)
方法 F
是使用舊的值來呼叫 i
,然後使用 G
的舊值來呼叫方法, i
最後, H
會使用的新值來呼叫方法 i
。For example, in F(i) + G(i++) * H(i)
, method F
is called using the old value of i
, then method G
is called with the old value of i
, and, finally, method H
is called with the new value of i
. 這與運算子優先順序不同且不相關。This is separate from and unrelated to operator precedence.
部分運算子可以 多載。Certain operators can be overloaded. 運算子多載可讓您針對一或兩個運算元都是使用者定義的類別或結構類型 (運算子 多載) 的作業指定使用者定義的運算子。Operator overloading permits user-defined operator implementations to be specified for operations where one or both of the operands are of a user-defined class or struct type (Operator overloading).
運算子優先順序和關聯性Operator precedence and associativity
當運算式包含多個運算子時,運算子的 *優先順序 _ 會控制個別運算子的評估順序。When an expression contains multiple operators, the *precedence _ of the operators controls the order in which the individual operators are evaluated. 例如,運算式 x + y _ z
會評估為 x + (y * z)
,因為 *
運算子的優先順序高於二元 +
運算子。For example, the expression x + y _ z
is evaluated as x + (y * z)
because the *
operator has higher precedence than the binary +
operator. 運算子優先順序是由其相關聯文法結果的定義所建立。The precedence of an operator is established by the definition of its associated grammar production. 例如, additive_expression 包含由或運算子分隔的一連串 multiplicative_expression +
-
,因此,和運算子的優先順序會低於 +
、和 -
*
/
%
運算子。For example, an additive_expression consists of a sequence of multiplicative_expression s separated by +
or -
operators, thus giving the +
and -
operators lower precedence than the *
, /
, and %
operators.
下表依優先順序從最高到最低的順序匯總所有運算子:The following table summarizes all operators in order of precedence from highest to lowest:
小節Section | 類別Category | 運算子Operators |
---|---|---|
主要運算式Primary expressions | 主要Primary | x.y f(x) a[x] x++ x-- new typeof default checked unchecked delegate x.y f(x) a[x] x++ x-- new typeof default checked unchecked delegate |
一元運算子Unary operators | 一元 (Unary)Unary | + - ! ~ ++x --x (T)x + - ! ~ ++x --x (T)x |
算術運算子Arithmetic operators | 乘法Multiplicative | * / % * / % |
算術運算子Arithmetic operators | 加法Additive | + - + - |
移位運算子Shift operators | ShiftShift | << >> << >> |
關係和類型測試運算子Relational and type-testing operators | 關係和型別測試Relational and type testing | < > <= >= is as < > <= >= is as |
關係和類型測試運算子Relational and type-testing operators | 等式Equality | == != == != |
邏輯運算子Logical operators | 邏輯 ANDLogical AND | & |
邏輯運算子Logical operators | 邏輯 XORLogical XOR | ^ |
邏輯運算子Logical operators | 邏輯 ORLogical OR | | |
條件邏輯運算子Conditional logical operators | 條件式 ANDConditional AND | && |
條件邏輯運算子Conditional logical operators | 條件式 ORConditional OR | || |
Null 聯合運算子The null coalescing operator | Null 聯合Null coalescing | ?? |
條件運算子Conditional operator | 條件式Conditional | ?: |
指派運算子, 匿名函數運算式Assignment operators, Anonymous function expressions | 指派和 lambda 運算式Assignment and lambda expression | = *= /= %= += -= <<= >>= &= ^= |= => = *= /= %= += -= <<= >>= &= ^= |= => |
當兩個優先順序相同的運算子之間有運算元時,運算子的「關聯性」會控制執行運算的順序:When an operand occurs between two operators with the same precedence, the associativity of the operators controls the order in which the operations are performed:
- 除了指派運算子和 null 聯合運算子之外,所有二元運算子都是 左方關聯 的,這表示作業是由左至右執行。Except for the assignment operators and the null coalescing operator, all binary operators are left-associative, meaning that operations are performed from left to right. 例如,
x + y + z
會判斷值為(x + y) + z
。For example,x + y + z
is evaluated as(x + y) + z
. - 指派運算子、null 聯合運算子和條件運算子 (
?:
) 是 右向關聯,這表示作業是由右至左執行。The assignment operators, the null coalescing operator and the conditional operator (?:
) are right-associative, meaning that operations are performed from right to left. 例如,x = y = z
會判斷值為x = (y = z)
。For example,x = y = z
is evaluated asx = (y = z)
.
您可以使用括弧來控制優先順序和關聯性。Precedence and associativity can be controlled using parentheses. 例如,x + y * z
會先將 y
乘以 z
,然後再將結果加到 x
,而 (x + y) * z
則會先將 x
與 y
相加,然後再將結果乘以 z
。For example, x + y * z
first multiplies y
by z
and then adds the result to x
, but (x + y) * z
first adds x
and y
and then multiplies the result by z
.
運算子多載Operator overloading
所有一元和二元運算子都具有可在任何運算式中自動使用的預先定義的實作為。All unary and binary operators have predefined implementations that are automatically available in any expression. 除了預先定義的執行之外,也可以藉由 operator
在類別和結構中包含宣告 (運算子) 來引入使用者定義的實作為。In addition to the predefined implementations, user-defined implementations can be introduced by including operator
declarations in classes and structs (Operators). 使用者定義運算子的執行一律優先于預先定義的運算子實作為:只有當沒有適用的使用者定義運算子實作為時,才會考慮預先定義的運算子實作為考慮,如 一元運算子 多載解析和 二元運算子多載解析中所述。User-defined operator implementations always take precedence over predefined operator implementations: Only when no applicable user-defined operator implementations exist will the predefined operator implementations be considered, as described in Unary operator overload resolution and Binary operator overload resolution.
可多載的 一元運算子 為:The overloadable unary operators are:
+ - ! ~ ++ -- true false
雖然 true
和不 false
會在運算式中明確使用 (而且不會包含在運算子優先順序和關聯性) 的優先順序資料表中,但它們被視為運算子,因為它們是在數個運算式內容中叫用:布林運算式 (布林運算式) 以及條件式邏輯 運算子 (條件式邏輯運算子) 的運算式。Although true
and false
are not used explicitly in expressions (and therefore are not included in the precedence table in Operator precedence and associativity), they are considered operators because they are invoked in several expression contexts: boolean expressions (Boolean expressions) and expressions involving the conditional (Conditional operator), and conditional logical operators (Conditional logical operators).
可多載的 二元運算子 為:The overloadable binary operators are:
+ - * / % & | ^ << >> == != > < >= <=
只有上面列出的運算子可以多載。Only the operators listed above can be overloaded. 尤其是,無法多載成員存取、方法調用,或、、、、、、、、、、、 =
&&
||
??
?:
=>
checked
unchecked
new
typeof
default
as
和 is
運算子。In particular, it is not possible to overload member access, method invocation, or the =
, &&
, ||
, ??
, ?:
, =>
, checked
, unchecked
, new
, typeof
, default
, as
, and is
operators.
二元運算子多載時,對應的指派運算子 (若有) 也會隱含地多載。When a binary operator is overloaded, the corresponding assignment operator, if any, is also implicitly overloaded. 例如,運算子的多載 *
也是運算子的多載 *=
。For example, an overload of operator *
is also an overload of operator *=
. 這會在 複合指派中進一步說明。This is described further in Compound assignment. 請注意,指派運算子本身 (=
) 不能多載。Note that the assignment operator itself (=
) cannot be overloaded. 指派一律會將值的簡單位複本執行到變數中。An assignment always performs a simple bit-wise copy of a value into a variable.
轉換作業(例如 (T)x
)會藉由提供使用者定義的轉換 (使用者定義的轉換) 來多載。Cast operations, such as (T)x
, are overloaded by providing user-defined conversions (User-defined conversions).
元素存取(例如 a[x]
)不會被視為可多載的運算子。Element access, such as a[x]
, is not considered an overloadable operator. 相反地, (索引子) 的索引子支援使用者定義的索引。Instead, user-defined indexing is supported through indexers (Indexers).
在運算式中,運算子會使用運算子標記法來參考,而在宣告中,運算子會使用函式標記法來參考。In expressions, operators are referenced using operator notation, and in declarations, operators are referenced using functional notation. 下表顯示一元和二元運算子的運算子和函數標記法之間的關聯性。The following table shows the relationship between operator and functional notations for unary and binary operators. 在第一個專案中, op 表示任何可多載的一元前置運算子。In the first entry, op denotes any overloadable unary prefix operator. 在第二個專案中, op 代表一元後置 ++
和 --
運算子。In the second entry, op denotes the unary postfix ++
and --
operators. 在第三個專案中, op 表示任何可多載的二元運算子。In the third entry, op denotes any overloadable binary operator.
運算子標記法Operator notation | 功能標記法Functional notation |
---|---|
op x |
operator op(x) |
x op |
operator op(x) |
x op y |
operator op(x,y) |
使用者定義運算子宣告一律需要至少一個參數必須是包含運算子宣告的類別或結構類型。User-defined operator declarations always require at least one of the parameters to be of the class or struct type that contains the operator declaration. 因此,使用者定義的運算子不可能具有與預先定義之運算子相同的簽章。Thus, it is not possible for a user-defined operator to have the same signature as a predefined operator.
使用者定義運算子聲明無法修改運算子的語法、優先順序或關聯性。User-defined operator declarations cannot modify the syntax, precedence, or associativity of an operator. 例如, /
運算子一律是二元運算子,且一律具有在 運算子優先順序和關聯性中指定的優先順序層級,而且一律為左方關聯。For example, the /
operator is always a binary operator, always has the precedence level specified in Operator precedence and associativity, and is always left-associative.
雖然使用者定義的運算子有可能執行 pleases 的任何計算,但強烈建議您不要使用產生的結果,而不是以直覺方式產生的結果。While it is possible for a user-defined operator to perform any computation it pleases, implementations that produce results other than those that are intuitively expected are strongly discouraged. 例如,的執行 operator ==
應該比較兩個運算元是否相等,並傳回適當的 bool
結果。For example, an implementation of operator ==
should compare the two operands for equality and return an appropriate bool
result.
透過條件式邏輯運算子,主要運算式中個別運算子的描述會指定運算子的預先定義執行,以及適用于每個運算子的任何其他規則。The descriptions of individual operators in Primary expressions through Conditional logical operators specify the predefined implementations of the operators and any additional rules that apply to each operator. 這些描述會使用詞彙 一元運算子 多載解析 _、 _二元運算子*_ 多載解析和 _ 數值提升 *,其定義可在下列各節中找到。The descriptions make use of the terms unary operator overload resolution _, _binary operator overload resolution_, and _numeric promotion**, definitions of which are found in the following sections.
一元運算子多載解析Unary operator overload resolution
或形式的作業 op x
x op
,其中是可多載的 op
一元運算子,而 x
是類型的運算式,其 X
處理方式如下:An operation of the form op x
or x op
, where op
is an overloadable unary operator, and x
is an expression of type X
, is processed as follows:
- 針對作業所提供的候選使用者定義運算子集合
X
operator op(x)
,是使用 候選使用者定義運算子的規則來決定。The set of candidate user-defined operators provided byX
for the operationoperator op(x)
is determined using the rules of Candidate user-defined operators. - 如果候選的使用者定義運算子集合不是空的,則這會成為作業的候選運算子集合。If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. 否則,預先定義的一元實
operator op
組(包括其提升形式)會成為作業的候選運算子集合。Otherwise, the predefined unaryoperator op
implementations, including their lifted forms, become the set of candidate operators for the operation. 指定運算子的預先定義的實 (主要運算式 和 一元運算子) 指定于運算子的描述中。The predefined implementations of a given operator are specified in the description of the operator (Primary expressions and Unary operators). - 多載解析的多載解析 規則會套用 至候選運算子集合,以選取與引數清單相關的最佳運算子
(x)
,而且這個運算子會成為多載解析程式的結果。The overload resolution rules of Overload resolution are applied to the set of candidate operators to select the best operator with respect to the argument list(x)
, and this operator becomes the result of the overload resolution process. 如果多載解析無法選取單一最佳運算子,則會發生系結階段錯誤。If overload resolution fails to select a single best operator, a binding-time error occurs.
二元運算子多載解析Binary operator overload resolution
表單的作業 x op y
(其中是可多載的 op
二元運算子) x
是類型的運算式, X
而 y
是類型的運算式,其 Y
處理方式如下:An operation of the form x op y
, where op
is an overloadable binary operator, x
is an expression of type X
, and y
is an expression of type Y
, is processed as follows:
- 由和針對作業所提供的候選使用者定義運算子集合
X
Y
operator op(x,y)
。The set of candidate user-defined operators provided byX
andY
for the operationoperator op(x,y)
is determined. 此集合是由所提供之候選運算子的聯集X
以及提供的候選運算子所組成Y
,每個都是使用 候選使用者定義運算子的規則來決定。The set consists of the union of the candidate operators provided byX
and the candidate operators provided byY
, each determined using the rules of Candidate user-defined operators. 如果X
和是Y
相同的型別,或者如果X
和Y
是衍生自通用基底型別,則共用的候選運算子只會在合併的集合中進行。IfX
andY
are the same type, or ifX
andY
are derived from a common base type, then shared candidate operators only occur in the combined set once. - 如果候選的使用者定義運算子集合不是空的,則這會成為作業的候選運算子集合。If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. 否則,預先定義的二進位執行
operator op
(包括其提升形式)會成為作業的候選運算子集合。Otherwise, the predefined binaryoperator op
implementations, including their lifted forms, become the set of candidate operators for the operation. 指定運算子的預先定義的實作為透過條件式邏輯運算子) ,在運算子 (算術運算子的描述中指定。The predefined implementations of a given operator are specified in the description of the operator (Arithmetic operators through Conditional logical operators). 針對預先定義的列舉和委派運算子,唯一考慮的運算子是由列舉或委派型別所定義的運算子,也就是其中一個運算元的系結時間型別。For predefined enum and delegate operators, the only operators considered are those defined by an enum or delegate type that is the binding-time type of one of the operands. - 多載解析的多載解析 規則會套用 至候選運算子集合,以選取與引數清單相關的最佳運算子
(x,y)
,而且這個運算子會成為多載解析程式的結果。The overload resolution rules of Overload resolution are applied to the set of candidate operators to select the best operator with respect to the argument list(x,y)
, and this operator becomes the result of the overload resolution process. 如果多載解析無法選取單一最佳運算子,則會發生系結階段錯誤。If overload resolution fails to select a single best operator, a binding-time error occurs.
候選的使用者定義運算子Candidate user-defined operators
如果有型別 T
和作業 operator op(A)
,其中 op
是可多載的運算子,而且 A
是引數清單,所提供的候選使用者定義運算子 T
集會 operator op(A)
依照下列方式決定:Given a type T
and an operation operator op(A)
, where op
is an overloadable operator and A
is an argument list, the set of candidate user-defined operators provided by T
for operator op(A)
is determined as follows:
- 判斷類型
T0
。Determine the typeT0
. 如果T
是可為 null 的型別,T0
則為其基礎類型,否則T0
等於T
。IfT
is a nullable type,T0
is its underlying type, otherwiseT0
is equal toT
. - 針對中的所有宣告
operator op
T0
和這類運算子的所有形式,如果至少有一個運算子適用 (適用 的函式成員) 與引數清單有關A
,則候選運算子集會由中的所有這類適用運算子組成T0
。For alloperator op
declarations inT0
and all lifted forms of such operators, if at least one operator is applicable (Applicable function member) with respect to the argument listA
, then the set of candidate operators consists of all such applicable operators inT0
. - 否則,如果
T0
為object
,候選運算子的集合就會是空的。Otherwise, ifT0
isobject
, the set of candidate operators is empty. - 否則,所提供的候選運算子集會
T0
是的直接基類所提供的候選運算子集T0
,T0
如果是型別參數,則為的有效基類T0
。Otherwise, the set of candidate operators provided byT0
is the set of candidate operators provided by the direct base class ofT0
, or the effective base class ofT0
ifT0
is a type parameter.
數值升階Numeric promotions
數值提升是由自動執行預先定義之一元和二元數值運算子之運算元的某些隱含轉換所組成。Numeric promotion consists of automatically performing certain implicit conversions of the operands of the predefined unary and binary numeric operators. 數值升級並非不同的機制,而是將多載解析套用至預先定義之運算子的效果。Numeric promotion is not a distinct mechanism, but rather an effect of applying overload resolution to the predefined operators. 數值升階明確地不會影響使用者定義運算子的評估,雖然可以實行使用者定義運算子來展現類似的效果。Numeric promotion specifically does not affect evaluation of user-defined operators, although user-defined operators can be implemented to exhibit similar effects.
作為數值升級的範例,請考慮二元運算子的預先定義的實值 *
:As an example of numeric promotion, consider the predefined implementations of the binary *
operator:
int operator *(int x, int y);
uint operator *(uint x, uint y);
long operator *(long x, long y);
ulong operator *(ulong x, ulong y);
float operator *(float x, float y);
double operator *(double x, double y);
decimal operator *(decimal x, decimal y);
當多載解析規則 (多載 解析 規則時,) 會套用至這組運算子,其效果是選取第一個運算子,其中的隱含轉換存在於運算元類型。When overload resolution rules (Overload resolution) are applied to this set of operators, the effect is to select the first of the operators for which implicit conversions exist from the operand types. 例如,針對作業 b * s
,其中為, b
byte
且 s
為,多載 short
解析會選取 operator *(int,int)
為最佳運算子。For example, for the operation b * s
, where b
is a byte
and s
is a short
, overload resolution selects operator *(int,int)
as the best operator. 因此,效果是, b
和 s
會轉換成 int
,而結果的類型是 int
。Thus, the effect is that b
and s
are converted to int
, and the type of the result is int
. 同樣地,對於作業 i * d
而言,如果是,則為,多載 i
int
d
double
解析會選取 operator *(double,double)
做為最佳運算子。Likewise, for the operation i * d
, where i
is an int
and d
is a double
, overload resolution selects operator *(double,double)
as the best operator.
一元數值提升Unary numeric promotions
針對預先定義的 +
、 -
和一元運算子的運算元進行一元數值提升 ~
。Unary numeric promotion occurs for the operands of the predefined +
, -
, and ~
unary operators. 一元數值提升只包含 sbyte
將、、、或類型的運算元轉換 byte
short
ushort
char
成類型 int
。Unary numeric promotion simply consists of converting operands of type sbyte
, byte
, short
, ushort
, or char
to type int
. 此外,對於一元 -
運算子,一元數值提升會將類型的運算元轉換 uint
成類型 long
。Additionally, for the unary -
operator, unary numeric promotion converts operands of type uint
to type long
.
二進位數值升級Binary numeric promotions
針對預先定義的、、、、、、、、、、、、 +
-
*
/
%
&
|
^
==
!=
>
<
>=
和 <=
二元運算子的運算元,會發生二進位數值升級。Binary numeric promotion occurs for the operands of the predefined +
, -
, *
, /
, %
, &
, |
, ^
, ==
, !=
, >
, <
, >=
, and <=
binary operators. 二進位數值升階會隱含地將這兩個運算元轉換成一般型別,如果是非關聯式運算子,也會成為作業的結果型別。Binary numeric promotion implicitly converts both operands to a common type which, in case of the non-relational operators, also becomes the result type of the operation. 二進位數值升階包含套用下列規則,順序如下所示:Binary numeric promotion consists of applying the following rules, in the order they appear here:
- 如果任一個運算元的類型為
decimal
,則會將另一個運算元轉換成類型decimal
,如果另一個運算元的類型是或,就會發生系結階段錯誤float
double
。If either operand is of typedecimal
, the other operand is converted to typedecimal
, or a binding-time error occurs if the other operand is of typefloat
ordouble
. - 否則,如果任一個運算元的類型為
double
,則會將另一個運算元轉換成類型double
。Otherwise, if either operand is of typedouble
, the other operand is converted to typedouble
. - 否則,如果任一個運算元的類型為
float
,則會將另一個運算元轉換成類型float
。Otherwise, if either operand is of typefloat
, the other operand is converted to typefloat
. - 否則,如果任一個運算元的類型為
ulong
,則會將另一個運算元轉換成類型ulong
,如果另一個運算元的類型為sbyte
、short
、或,則會發生系結階段錯誤int
long
。Otherwise, if either operand is of typeulong
, the other operand is converted to typeulong
, or a binding-time error occurs if the other operand is of typesbyte
,short
,int
, orlong
. - 否則,如果任一個運算元的類型為
long
,則會將另一個運算元轉換成類型long
。Otherwise, if either operand is of typelong
, the other operand is converted to typelong
. - 否則,如果任一個運算元的類型為
uint
,而另一個運算元的類型為sbyte
、short
或int
,則這兩個運算元會轉換為類型long
。Otherwise, if either operand is of typeuint
and the other operand is of typesbyte
,short
, orint
, both operands are converted to typelong
. - 否則,如果任一個運算元的類型為
uint
,則會將另一個運算元轉換成類型uint
。Otherwise, if either operand is of typeuint
, the other operand is converted to typeuint
. - 否則,會將這兩個運算元轉換成類型
int
。Otherwise, both operands are converted to typeint
.
請注意,第一個規則不允許混 decimal
用類型與 double
和類型的任何作業 float
。Note that the first rule disallows any operations that mix the decimal
type with the double
and float
types. 規則是因為 decimal
類型和和類型之間沒有隱含轉換 double
float
。The rule follows from the fact that there are no implicit conversions between the decimal
type and the double
and float
types.
另請注意, ulong
當另一個運算元是帶正負號的整數類資料類型時,運算元不能是類型。Also note that it is not possible for an operand to be of type ulong
when the other operand is of a signed integral type. 原因是沒有整數類資料類型可以代表的完整範圍以及 ulong
帶正負號的整數類資料類型。The reason is that no integral type exists that can represent the full range of ulong
as well as the signed integral types.
在上述兩種情況下,cast 運算式可以用來將一個運算元明確轉換成與另一個運算元相容的型別。In both of the above cases, a cast expression can be used to explicitly convert one operand to a type that is compatible with the other operand.
在範例中In the example
decimal AddPercent(decimal x, double percent) {
return x * (1.0 + percent / 100.0);
}
發生系結時期錯誤,因為 decimal
無法乘 double
。a binding-time error occurs because a decimal
cannot be multiplied by a double
. 錯誤的解決方式是將第二個運算元明確轉換為,如下所示 decimal
:The error is resolved by explicitly converting the second operand to decimal
, as follows:
decimal AddPercent(decimal x, double percent) {
return x * (decimal)(1.0 + percent / 100.0);
}
提起運算子Lifted operators
提升運算子 允許在不可為 null 的實值型別上操作的預先定義和使用者定義運算子,也可用於這些類型的可為 null 形式。Lifted operators permit predefined and user-defined operators that operate on non-nullable value types to also be used with nullable forms of those types. 從符合特定需求的預先定義和使用者定義運算子來建立提升運算子,如下列所述:Lifted operators are constructed from predefined and user-defined operators that meet certain requirements, as described in the following:
針對一元運算子For the unary operators
+ ++ - -- ! ~
如果運算元和結果型別都不是可為 null 的實值型別,則會有運算子的形式存在。a lifted form of an operator exists if the operand and result types are both non-nullable value types. 藉由將單一修飾詞加入
?
至運算元和結果型別,即可建立產生的形式。The lifted form is constructed by adding a single?
modifier to the operand and result types. 如果運算元為 null,則提升運算子會產生 null 值。The lifted operator produces a null value if the operand is null. 否則,提起運算子會解除封裝運算元、套用基礎運算子,然後包裝結果。Otherwise, the lifted operator unwraps the operand, applies the underlying operator, and wraps the result.二元運算子的For the binary operators
+ - * / % & | ^ << >>
如果運算元和結果型別都是不可為 null 的實值型別,則會有運算子的形式存在。a lifted form of an operator exists if the operand and result types are all non-nullable value types. 產生的形式是藉由將單一修飾詞加入
?
至每個運算元和結果型別來構成。The lifted form is constructed by adding a single?
modifier to each operand and result type. 如果其中一或兩個運算元為 null,則會產生 null 值, (例外狀況&
為|
類型的和運算子bool?
,如 布林邏輯運算子) 中所述。The lifted operator produces a null value if one or both operands are null (an exception being the&
and|
operators of thebool?
type, as described in Boolean logical operators). 否則,提起運算子會解除包裝運算元、套用基礎運算子,並包裝結果。Otherwise, the lifted operator unwraps the operands, applies the underlying operator, and wraps the result.針對等號比較運算子For the equality operators
== !=
如果運算元型別同時為不可為 null 的實值型別,且結果型別為,則會有運算子的形式存在
bool
。a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type isbool
. 藉由將單一修飾詞加入?
至每個運算元類型,即可建立此形式。The lifted form is constructed by adding a single?
modifier to each operand type. 提起運算子會將兩個 null 值視為相等,而 null 值不會與任何非 null 值相等。The lifted operator considers two null values equal, and a null value unequal to any non-null value. 如果這兩個運算元都不是 null,則提升運算子會解除包裝運算元,並套用基礎運算子來產生bool
結果。If both operands are non-null, the lifted operator unwraps the operands and applies the underlying operator to produce thebool
result.針對關聯式運算子For the relational operators
< > <= >=
如果運算元型別同時為不可為 null 的實值型別,且結果型別為,則會有運算子的形式存在
bool
。a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type isbool
. 藉由將單一修飾詞加入?
至每個運算元類型,即可建立此形式。The lifted form is constructed by adding a single?
modifier to each operand type.false
如果一個或兩個運算元都是 null,則提升運算子會產生值。The lifted operator produces the valuefalse
if one or both operands are null. 否則,提起運算子會解除包裝運算元,並套用基礎運算子來產生bool
結果。Otherwise, the lifted operator unwraps the operands and applies the underlying operator to produce thebool
result.
成員查詢Member lookup
成員查閱是一種進程,會決定型別內容中的名稱意義。A member lookup is the process whereby the meaning of a name in the context of a type is determined. 成員查閱可以在評估 simple_name 的 (簡單名稱) 或運算式中 member_access (成員存取) 的過程中發生。A member lookup can occur as part of evaluating a simple_name (Simple names) or a member_access (Member access) in an expression. 如果 simple_name 或 member_access 是做為 invocation_expression (方法調用) 的 primary_expression 發生,則會叫用該成員。If the simple_name or member_access occurs as the primary_expression of an invocation_expression (Method invocations), the member is said to be invoked.
如果成員是方法或事件,或者如果它是常數、委派型別的欄位或屬性 (委派) 或 dynamic
(動態類型) 的型別,則會將該成員視為 >invocable。If a member is a method or event, or if it is a constant, field or property of either a delegate type (Delegates) or the type dynamic
(The dynamic type), then the member is said to be invocable.
成員查閱不僅會考慮成員的名稱,也會考慮成員擁有的類型參數數目,以及成員是否可存取。Member lookup considers not only the name of a member but also the number of type parameters the member has and whether the member is accessible. 基於成員查閱的目的,泛型方法和嵌套泛型型別具有其各自宣告中指定的類型參數數目,而所有其他成員都有零型別參數。For the purposes of member lookup, generic methods and nested generic types have the number of type parameters indicated in their respective declarations and all other members have zero type parameters.
N
類型中具有類型參數之名稱的成員查閱 K
T
會以下列方式處理:A member lookup of a name N
with K
type parameters in a type T
is processed as follows:
- 首先,會決定一組名為的可存取成員
N
:First, a set of accessible members namedN
is determined:- 如果
T
是型別參數,則集合是N
在指定為主要條件約束或次要條件約束的每個類型中,所命名之可存取成員集合的聯集T
,以及中所命名的可存取成員集合) (N
object
。IfT
is a type parameter, then the set is the union of the sets of accessible members namedN
in each of the types specified as a primary constraint or secondary constraint (Type parameter constraints) forT
, along with the set of accessible members namedN
inobject
. - 否則,此集合會由中命名的所有可存取 (成員存取) 成員
N
T
,包括繼承的成員以及中所命名的可存取成員N
object
。Otherwise, the set consists of all accessible (Member access) members namedN
inT
, including inherited members and the accessible members namedN
inobject
. 如果T
是一種結構化型別,則會藉由替代型別引數來取得成員集,如 結構化類型的成員中所述。IfT
is a constructed type, the set of members is obtained by substituting type arguments as described in Members of constructed types. 包含修飾詞的成員override
將會從集合中排除。Members that include anoverride
modifier are excluded from the set.
- 如果
- 接下來,如果
K
是零,則會移除宣告包含類型參數的所有巢狀型別。Next, ifK
is zero, all nested types whose declarations include type parameters are removed. 如果不K
是零,則會移除具有不同類型參數數目的所有成員。IfK
is not zero, all members with a different number of type parameters are removed. 請注意,如果K
是零,則不會移除具有型別參數的方法,因為型別推斷程式 (型別推斷) 可能可以推斷型別引數。Note that whenK
is zero, methods having type parameters are not removed, since the type inference process (Type inference) might be able to infer the type arguments. - 接下來,如果叫用 成員,則 會從集合中移除所有的非 >invocable 成員。Next, if the member is invoked, all non-invocable members are removed from the set.
- 接著,會從集合中移除其他成員隱藏的成員。Next, members that are hidden by other members are removed from the set. 針對集合中的每個成員
S.M
,其中是宣告成員的型別,S
M
則會套用下列規則:For every memberS.M
in the set, whereS
is the type in which the memberM
is declared, the following rules are applied:- 如果
M
是常數、欄位、屬性、事件或列舉成員,則基底類型中宣告的所有成員S
都會從集合中移除。IfM
is a constant, field, property, event, or enumeration member, then all members declared in a base type ofS
are removed from the set. - 如果
M
是型別宣告,則會從集合中移除基底類型中宣告的所有非型別S
,而且具有與基底類型中宣告之相同類型參數數目的所有類型宣告,M
S
都會從集合中移除。IfM
is a type declaration, then all non-types declared in a base type ofS
are removed from the set, and all type declarations with the same number of type parameters asM
declared in a base type ofS
are removed from the set. - 如果
M
是方法,則基底類型中宣告的所有非方法成員S
都會從集合中移除。IfM
is a method, then all non-method members declared in a base type ofS
are removed from the set.
- 如果
- 接下來,會從集合中移除類別成員隱藏的介面成員。Next, interface members that are hidden by class members are removed from the set. 只有當
T
是型別參數,而且T
具有object
非空白的有效介面集 (類型參數條件約束) 時,此步驟才會有作用。This step only has an effect ifT
is a type parameter andT
has both an effective base class other thanobject
and a non-empty effective interface set (Type parameter constraints). 針對集合中的每個成員S.M
,其中S
是宣告成員的類型M
,如果是以外的類別宣告,則會套用下列規則S
object
:For every memberS.M
in the set, whereS
is the type in which the memberM
is declared, the following rules are applied ifS
is a class declaration other thanobject
:- 如果
M
是常數、欄位、屬性、事件、列舉成員或型別宣告,則會從集合中移除在介面宣告中宣告的所有成員。IfM
is a constant, field, property, event, enumeration member, or type declaration, then all members declared in an interface declaration are removed from the set. - 如果
M
是方法,則會從集合中移除介面宣告中宣告的所有非方法成員,並且會從集合中移除所有具有相同簽章的方法M
。IfM
is a method, then all non-method members declared in an interface declaration are removed from the set, and all methods with the same signature asM
declared in an interface declaration are removed from the set.
- 如果
- 最後,移除隱藏的成員之後,就會判斷查閱的結果:Finally, having removed hidden members, the result of the lookup is determined:
- 如果集合是由非方法的單一成員所組成,則這個成員是查閱的結果。If the set consists of a single member that is not a method, then this member is the result of the lookup.
- 否則,如果集合只包含方法,則此方法群組就是查閱的結果。Otherwise, if the set contains only methods, then this group of methods is the result of the lookup.
- 否則,查閱會不明確,而且會發生系結階段錯誤。Otherwise, the lookup is ambiguous, and a binding-time error occurs.
針對類型參數和介面以外之類型中的成員查閱,以及繼承鏈中的成員查閱, (繼承鏈中的每個介面都只有零個或一個直接基底介面) ,則查閱規則的效果只是衍生的成員會隱藏具有相同名稱或簽章的基底成員。For member lookups in types other than type parameters and interfaces, and member lookups in interfaces that are strictly single-inheritance (each interface in the inheritance chain has exactly zero or one direct base interface), the effect of the lookup rules is simply that derived members hide base members with the same name or signature. 這類單一繼承查閱永遠不可混淆。Such single-inheritance lookups are never ambiguous. 介面成員存取中描述了可能會從多個繼承介面中成員查閱產生的多義性。The ambiguities that can possibly arise from member lookups in multiple-inheritance interfaces are described in Interface member access.
基底類型Base types
針對成員查閱的目的,會將類型 T
視為具有下列基底類型:For purposes of member lookup, a type T
is considered to have the following base types:
- 如果
T
為object
,則表示T
沒有基底類型。IfT
isobject
, thenT
has no base type. - 如果
T
是 enum_type,的基底類型T
為類別類型System.Enum
、System.ValueType
和object
。IfT
is an enum_type, the base types ofT
are the class typesSystem.Enum
,System.ValueType
, andobject
. - 如果
T
是 struct_type,的基底類型T
為類別類型System.ValueType
和object
。IfT
is a struct_type, the base types ofT
are the class typesSystem.ValueType
andobject
. - 如果
T
是 class_type,的基底類型T
就是的基類T
,包括類別型別object
。IfT
is a class_type, the base types ofT
are the base classes ofT
, including the class typeobject
. - 如果
T
是 interface_type,的基底類型T
為的基底介面T
和類別類型object
。IfT
is an interface_type, the base types ofT
are the base interfaces ofT
and the class typeobject
. - 如果
T
是 array_type,的基底類型T
為類別類型System.Array
和object
。IfT
is an array_type, the base types ofT
are the class typesSystem.Array
andobject
. - 如果
T
是 delegate_type,的基底類型T
為類別類型System.Delegate
和object
。IfT
is a delegate_type, the base types ofT
are the class typesSystem.Delegate
andobject
.
函式成員Function members
函數成員是包含可執行語句的成員。Function members are members that contain executable statements. 函數成員一律為類型的成員,而且不可以是命名空間的成員。Function members are always members of types and cannot be members of namespaces. C # 會定義下列類別的函數成員:C# defines the following categories of function members:
- 方法Methods
- 屬性Properties
- 事件Events
- 索引子Indexers
- 使用者定義的運算子User-defined operators
- 實例的函式Instance constructors
- 靜態建構函式Static constructors
- 解構函式Destructors
除了無法明確叫用) 的析構函數和靜態函式 (之外,函式成員中包含的語句是透過函數成員調用來執行。Except for destructors and static constructors (which cannot be invoked explicitly), the statements contained in function members are executed through function member invocations. 撰寫函數成員調用的實際語法取決於特定的函數成員類別。The actual syntax for writing a function member invocation depends on the particular function member category.
引數清單 (自 變數清單) 函數成員調用會提供函數成員之參數的實際值或變數參考。The argument list (Argument lists) of a function member invocation provides actual values or variable references for the parameters of the function member.
泛型方法的調用可採用型別推斷來判斷要傳遞給方法的型別引數集。Invocations of generic methods may employ type inference to determine the set of type arguments to pass to the method. 此程式會在 型別推斷中描述。This process is described in Type inference.
方法的調用、索引子、運算子和實例的函式會採用多載解析來判斷要叫用的一組候選函數成員。Invocations of methods, indexers, operators and instance constructors employ overload resolution to determine which of a candidate set of function members to invoke. 此程式會在多載 解析中描述。This process is described in Overload resolution.
一旦在系結階段識別特定的函式成員(可能是透過多載解析),就會在動態多載 解析的編譯時間檢查中描述叫用函數成員的實際執行時間程式。Once a particular function member has been identified at binding-time, possibly through overload resolution, the actual run-time process of invoking the function member is described in Compile-time checking of dynamic overload resolution.
下表摘要說明在包含可明確叫用之函式成員六個類別的結構中所發生的處理。The following table summarizes the processing that takes place in constructs involving the six categories of function members that can be explicitly invoked. 在資料表中, e
、 x
、 y
和 value
表示分類為變數或值的運算式, T
表示分類為類型的運算式、 F
方法的簡單名稱,以及 P
屬性的簡單名稱。In the table, e
, x
, y
, and value
indicate expressions classified as variables or values, T
indicates an expression classified as a type, F
is the simple name of a method, and P
is the simple name of a property.
構建Construct | 範例Example | 說明Description |
---|---|---|
方法引動過程Method invocation | F(x,y) |
套用多載解析,以選取 F 包含類別或結構中的最佳方法。Overload resolution is applied to select the best method F in the containing class or struct. 使用引數清單叫用方法 (x,y) 。The method is invoked with the argument list (x,y) . 如果方法不是 static ,則實例運算式為 this 。If the method is not static , the instance expression is this . |
T.F(x,y) |
套用多載解析,以選取 F 類別或結構中的最佳方法 T 。Overload resolution is applied to select the best method F in the class or struct T . 如果方法不是,就會發生系結階段錯誤 static 。A binding-time error occurs if the method is not static . 使用引數清單叫用方法 (x,y) 。The method is invoked with the argument list (x,y) . |
|
e.F(x,y) |
使用多載解析來選取類別、結構或類型所提供之介面中的最佳方法 F e 。Overload resolution is applied to select the best method F in the class, struct, or interface given by the type of e . 如果方法為,就會發生系結階段錯誤 static 。A binding-time error occurs if the method is static . 使用實例運算式 e 和引數清單叫用方法 (x,y) 。The method is invoked with the instance expression e and the argument list (x,y) . |
|
屬性存取Property access | P |
get P 會叫用包含類別或結構中之屬性的存取子。The get accessor of the property P in the containing class or struct is invoked. 如果是唯讀的,則會發生編譯時期錯誤 P 。A compile-time error occurs if P is write-only. 如果不 P 是 static ,則實例運算式為 this 。If P is not static , the instance expression is this . |
P = value |
set P 使用引數清單叫用包含類別或結構中之屬性的存取子 (value) 。The set accessor of the property P in the containing class or struct is invoked with the argument list (value) . 如果是唯讀的,則會發生編譯時期錯誤 P 。A compile-time error occurs if P is read-only. 如果不 P 是 static ,則實例運算式為 this 。If P is not static , the instance expression is this . |
|
T.P |
在 get P 類別或結構中叫用屬性的存取子 T 。The get accessor of the property P in the class or struct T is invoked. 如果 P 不是 static 或 P 為唯讀,就會發生編譯時期錯誤。A compile-time error occurs if P is not static or if P is write-only. |
|
T.P = value |
set P T 使用引數清單叫用類別或結構中屬性的存取子 (value) 。The set accessor of the property P in the class or struct T is invoked with the argument list (value) . 如果 P 不是 static 或唯讀,就會發生編譯時期錯誤 P 。A compile-time error occurs if P is not static or if P is read-only. |
|
e.P |
get P 類別、結構或型別中所指定之屬性的存取子 e 會以實例運算式叫用 e 。The get accessor of the property P in the class, struct, or interface given by the type of e is invoked with the instance expression e . 如果 P 是或,則會發生系結階段錯誤 static P 。A binding-time error occurs if P is static or if P is write-only. |
|
e.P = value |
set P e 使用實例運算式 e 和引數清單叫用之型別的類別、結構或介面中的屬性存取子 (value) 。The set accessor of the property P in the class, struct, or interface given by the type of e is invoked with the instance expression e and the argument list (value) . 如果 P 為, static 或如果是唯讀的,則會發生系結階段錯誤 P 。A binding-time error occurs if P is static or if P is read-only. |
|
事件存取Event access | E += value |
叫 add E 用包含類別或結構中事件的存取子。The add accessor of the event E in the containing class or struct is invoked. 如果不 E 是靜態的,則實例運算式為 this 。If E is not static, the instance expression is this . |
E -= value |
叫 remove E 用包含類別或結構中事件的存取子。The remove accessor of the event E in the containing class or struct is invoked. 如果不 E 是靜態的,則實例運算式為 this 。If E is not static, the instance expression is this . |
|
T.E += value |
叫 add E 用類別或結構中的事件存取子 T 。The add accessor of the event E in the class or struct T is invoked. 如果不是靜態的,則會發生系結階段錯誤 E 。A binding-time error occurs if E is not static. |
|
T.E -= value |
叫 remove E 用類別或結構中的事件存取子 T 。The remove accessor of the event E in the class or struct T is invoked. 如果不是靜態的,則會發生系結階段錯誤 E 。A binding-time error occurs if E is not static. |
|
e.E += value |
add E 類別、結構或介面中的事件存取子 e 是使用實例運算式叫用的 e 。The add accessor of the event E in the class, struct, or interface given by the type of e is invoked with the instance expression e . 如果是靜態的,則會發生系結階段錯誤 E 。A binding-time error occurs if E is static. |
|
e.E -= value |
remove E 類別、結構或介面中的事件存取子 e 是使用實例運算式叫用的 e 。The remove accessor of the event E in the class, struct, or interface given by the type of e is invoked with the instance expression e . 如果是靜態的,則會發生系結階段錯誤 E 。A binding-time error occurs if E is static. |
|
索引子存取Indexer access | e[x,y] |
使用多載解析來選取類別、結構或類型 e 所指定之介面中的最佳索引子。Overload resolution is applied to select the best indexer in the class, struct, or interface given by the type of e. get 使用實例運算式 e 和引數清單叫用索引子的存取子 (x,y) 。The get accessor of the indexer is invoked with the instance expression e and the argument list (x,y) . 如果索引子是唯讀的,則會發生系結階段錯誤。A binding-time error occurs if the indexer is write-only. |
e[x,y] = value |
套用多載解析,以選取類別、結構或類型所提供之介面中的最佳索引子 e 。Overload resolution is applied to select the best indexer in the class, struct, or interface given by the type of e . set 使用實例運算式 e 和引數清單叫用索引子的存取子 (x,y,value) 。The set accessor of the indexer is invoked with the instance expression e and the argument list (x,y,value) . 如果索引子是唯讀的,則會發生系結階段錯誤。A binding-time error occurs if the indexer is read-only. |
|
運算子調用Operator invocation | -x |
您可以套用多載解析,以在類型指定的類別或結構中選取最佳一元運算子 x 。Overload resolution is applied to select the best unary operator in the class or struct given by the type of x . 使用引數清單叫用選取的運算子 (x) 。The selected operator is invoked with the argument list (x) . |
x + y |
會套用多載解析,以在和類型所指定的類別或結構中選取最佳的二元運算子 x y 。Overload resolution is applied to select the best binary operator in the classes or structs given by the types of x and y . 使用引數清單叫用選取的運算子 (x,y) 。The selected operator is invoked with the argument list (x,y) . |
|
實例函式呼叫Instance constructor invocation | new T(x,y) |
套用多載解析,以選取類別或結構中的最佳實例處理常式 T 。Overload resolution is applied to select the best instance constructor in the class or struct T . 使用引數清單叫用實例的函式 (x,y) 。The instance constructor is invoked with the argument list (x,y) . |
引數清單Argument lists
每個函式成員和委派調用都包含引數清單,可提供函數成員之參數的實際值或變數參考。Every function member and delegate invocation includes an argument list which provides actual values or variable references for the parameters of the function member. 指定函式成員調用之引數清單的語法,取決於函數成員類別目錄:The syntax for specifying the argument list of a function member invocation depends on the function member category:
- 針對實例的函式、方法、索引子和委派,會將引數指定為 argument_list,如下所述。For instance constructors, methods, indexers and delegates, the arguments are specified as an argument_list, as described below. 針對索引子,當叫
set
用存取子時,引數清單會另外包含指定為指派運算子右運算元的運算式。For indexers, when invoking theset
accessor, the argument list additionally includes the expression specified as the right operand of the assignment operator. - 若為屬性,當叫用存取子時,引數清單是空的
get
,而且會包含在叫用存取子時,指定為指派運算子右運算元的運算式set
。For properties, the argument list is empty when invoking theget
accessor, and consists of the expression specified as the right operand of the assignment operator when invoking theset
accessor. - 若為事件,引數清單是由指定為或運算子右運算元的運算式所組成
+=
-=
。For events, the argument list consists of the expression specified as the right operand of the+=
or-=
operator. - 如果是使用者定義的運算子,引數清單會包含一元運算子的單一運算元或二元運算子的兩個運算元。For user-defined operators, the argument list consists of the single operand of the unary operator or the two operands of the binary operator.
屬性 (屬性 的引數) 、事件 (事件) 以及使用者定義運算子 (運算子) 一律會以值參數的形式傳遞 (值參數) 。The arguments of properties (Properties), events (Events), and user-defined operators (Operators) are always passed as value parameters (Value parameters). 索引子 (索引子) 的引數一律會 以值 ( 參數的形式傳遞至 (參數陣列) 參數陣列) 或參數陣列。The arguments of indexers (Indexers) are always passed as value parameters (Value parameters) or parameter arrays (Parameter arrays). 這些函數成員類別不支援參考和輸出參數。Reference and output parameters are not supported for these categories of function members.
實例的函式、方法、索引子或委派調用的引數會指定為 argument_list:The arguments of an instance constructor, method, indexer or delegate invocation are specified as an argument_list:
argument_list
: argument (',' argument)*
;
argument
: argument_name? argument_value
;
argument_name
: identifier ':'
;
argument_value
: expression
| 'ref' variable_reference
| 'out' variable_reference
;
Argument_list 是由一或多個 引數(以逗號分隔)所組成。An argument_list consists of one or more argument s, separated by commas. 每個引數都包含一個選擇性的 argument_name ,後面接著一個 argument_value。Each argument consists of an optional argument_name followed by an argument_value. 具有 argument_name 的 引數 稱為 *具名引數 ,而 不含 argument_name 的引數 * 則是 *位置引數。An argument with an argument_name is referred to as a named argument _, whereas an _argument without an argument_name is a *positional argument. 位置引數在 _argument_list * 中的具名引數後面出現錯誤。It is an error for a positional argument to appear after a named argument in an _argument_list*.
Argument_value 可以採用下列其中一種形式:The argument_value can take one of the following forms:
- 運算式,表示引數會以值參數的形式傳遞 (值參數) 。An expression, indicating that the argument is passed as a value parameter (Value parameters).
- 關鍵字
ref
後面接著 Variable_reference (變數參考) ,表示會將引數做為參考參數傳遞 (參考參數) 。The keywordref
followed by a variable_reference (Variable references), indicating that the argument is passed as a reference parameter (Reference parameters). 必須明確指派變數 (明確 指派) ,才能將變數作為參考參數來傳遞。A variable must be definitely assigned (Definite assignment) before it can be passed as a reference parameter. 關鍵字out
後面接著 Variable_reference (變數參考) ,表示引數會以輸出參數的形式傳遞 (輸出參數) 。The keywordout
followed by a variable_reference (Variable references), indicating that the argument is passed as an output parameter (Output parameters). 在變數作為輸出參數傳遞的函式成員調用之後,會將變數視為明確指派 (明確 指派) 。A variable is considered definitely assigned (Definite assignment) following a function member invocation in which the variable is passed as an output parameter.
對應的參數Corresponding parameters
對於引數清單中的每個引數,函式成員或委派中都必須有對應的參數。For each argument in an argument list there has to be a corresponding parameter in the function member or delegate being invoked.
下列所使用的參數清單的判斷方式如下:The parameter list used in the following is determined as follows:
- 針對在類別中定義的虛擬方法和索引子,會從函式成員最特定的宣告或覆寫來挑選參數清單,從接收者的靜態類型開始,然後搜尋其基類。For virtual methods and indexers defined in classes, the parameter list is picked from the most specific declaration or override of the function member, starting with the static type of the receiver, and searching through its base classes.
- 針對介面方法和索引子,會挑選參數清單,形成最特定的成員定義,從介面類別型開始,然後搜尋基底介面。For interface methods and indexers, the parameter list is picked form the most specific definition of the member, starting with the interface type and searching through the base interfaces. 如果找不到唯一的參數清單,則會建立具有無法存取名稱且沒有選擇性參數的參數清單,讓調用無法使用具名引數或省略選擇性引數。If no unique parameter list is found, a parameter list with inaccessible names and no optional parameters is constructed, so that invocations cannot use named parameters or omit optional arguments.
- 若為部分方法,則會使用定義部分方法宣告的參數清單。For partial methods, the parameter list of the defining partial method declaration is used.
- 對於所有其他的函式成員和委派,只有單一參數清單,也就是使用的參數清單。For all other function members and delegates there is only a single parameter list, which is the one used.
引數或參數的位置定義為引數清單或參數清單中前面的引數或參數數目。The position of an argument or parameter is defined as the number of arguments or parameters preceding it in the argument list or parameter list.
函數成員引數的對應參數會依照下列方式建立:The corresponding parameters for function member arguments are established as follows:
- Argument_list 實例的函式、方法、索引子和委派的引數:Arguments in the argument_list of instance constructors, methods, indexers and delegates:
- 位置引數,在參數清單中相同位置的固定參數會與該參數相對應。A positional argument where a fixed parameter occurs at the same position in the parameter list corresponds to that parameter.
- 函式成員的位置引數,其以其正常形式叫用的參數陣列,會對應至參數陣列,此參數陣列必須在參數清單中的相同位置發生。A positional argument of a function member with a parameter array invoked in its normal form corresponds to the parameter array, which must occur at the same position in the parameter list.
- 函式成員的位置引數,該函式成員具有展開形式的參數陣列,而在參數清單中的相同位置沒有任何固定參數,則對應至參數陣列中的元素。A positional argument of a function member with a parameter array invoked in its expanded form, where no fixed parameter occurs at the same position in the parameter list, corresponds to an element in the parameter array.
- 具名引數會對應到參數清單中相同名稱的參數。A named argument corresponds to the parameter of the same name in the parameter list.
- 針對索引子,
set
叫用存取子時,指定為指派運算子右運算元的運算式會對應到存取子宣告的隱含value
參數set
。For indexers, when invoking theset
accessor, the expression specified as the right operand of the assignment operator corresponds to the implicitvalue
parameter of theset
accessor declaration.
- 針對屬性,當叫用存取子時,沒有
get
引數。For properties, when invoking theget
accessor there are no arguments.set
叫用存取子時,指定為指派運算子右運算元的運算式會對應到存取子宣告的隱含value
參數set
。When invoking theset
accessor, the expression specified as the right operand of the assignment operator corresponds to the implicitvalue
parameter of theset
accessor declaration. - 如果使用者定義的一元運算子 (包括轉換) ,則單一運算元會對應到運算子宣告的單一參數。For user-defined unary operators (including conversions), the single operand corresponds to the single parameter of the operator declaration.
- 如果是使用者定義的二元運算子,左運算元會對應到第一個參數,右邊的運算元則對應到運算子宣告的第二個參數。For user-defined binary operators, the left operand corresponds to the first parameter, and the right operand corresponds to the second parameter of the operator declaration.
引數清單的執行時間評估Run-time evaluation of argument lists
在執行時間處理函數成員調用時 (動態多載 解析) 的編譯時間檢查 ,引數清單的運算式或變數參考會依序從左至右評估,如下所示:During the run-time processing of a function member invocation (Compile-time checking of dynamic overload resolution), the expressions or variable references of an argument list are evaluated in order, from left to right, as follows:
- 如果是值參數,則會評估引數運算式,並對對應的參數類型執行隱含轉換 (隱含 轉換) 。For a value parameter, the argument expression is evaluated and an implicit conversion (Implicit conversions) to the corresponding parameter type is performed. 產生的值會成為函數成員調用中 value 參數的初始值。The resulting value becomes the initial value of the value parameter in the function member invocation.
- 若為參考或輸出參數,則會評估變數參考,而產生的儲存位置會變成函式成員調用中參數所代表的儲存位置。For a reference or output parameter, the variable reference is evaluated and the resulting storage location becomes the storage location represented by the parameter in the function member invocation. 如果指定為參考或輸出參數的變數參考是 reference_type 的陣列元素,則會執行執行時間檢查,以確保陣列的元素類型與參數的類型相同。If the variable reference given as a reference or output parameter is an array element of a reference_type, a run-time check is performed to ensure that the element type of the array is identical to the type of the parameter. 如果這項檢查失敗,
System.ArrayTypeMismatchException
就會擲回。If this check fails, aSystem.ArrayTypeMismatchException
is thrown.
方法、索引子和實例的函式可能會將最右邊的參數宣告為參數陣列, (參數 陣列) 。Methods, indexers, and instance constructors may declare their right-most parameter to be a parameter array (Parameter arrays). 這類函式成員的叫用方式是以其正常形式或其展開形式來叫用 (適用的函式 成員) :Such function members are invoked either in their normal form or in their expanded form depending on which is applicable (Applicable function member):
- 以一般形式叫用具有參數陣列的函式成員時,為參數陣列提供的引數必須是可隱含轉換的單一運算式, (隱含轉換) 至參數陣列類型。When a function member with a parameter array is invoked in its normal form, the argument given for the parameter array must be a single expression that is implicitly convertible (Implicit conversions) to the parameter array type. 在此情況下,參數陣列的運作方式與值參數完全相同。In this case, the parameter array acts precisely like a value parameter.
- 當以參數陣列的擴充形式叫用具有參數陣列的函式成員時,調用必須為參數陣列指定零個或更多位置引數,其中每個引數都是可隱含轉換的運算式, (隱含轉換) 為參數陣列的元素類型。When a function member with a parameter array is invoked in its expanded form, the invocation must specify zero or more positional arguments for the parameter array, where each argument is an expression that is implicitly convertible (Implicit conversions) to the element type of the parameter array. 在此情況下,叫用會使用與引數數目對應的長度來建立參數陣列類型的實例,並使用指定的引數值初始化陣列實例的專案,並使用新建立的陣列實例作為實際的引數。In this case, the invocation creates an instance of the parameter array type with a length corresponding to the number of arguments, initializes the elements of the array instance with the given argument values, and uses the newly created array instance as the actual argument.
引數清單的運算式一律會依照寫入的順序進行評估。The expressions of an argument list are always evaluated in the order they are written. 因此,範例Thus, the example
class Test
{
static void F(int x, int y = -1, int z = -2) {
System.Console.WriteLine("x = {0}, y = {1}, z = {2}", x, y, z);
}
static void Main() {
int i = 0;
F(i++, i++, i++);
F(z: i++, x: i++);
}
}
產生下列輸出produces the output
x = 0, y = 1, z = 2
x = 4, y = -1, z = 3
陣列共變數規則 (陣列共 變數) 允許陣列類型的值 A[]
為數組類型實例的參考 B[]
,但前提是已有隱含的參考轉換 B
A
。The array co-variance rules (Array covariance) permit a value of an array type A[]
to be a reference to an instance of an array type B[]
, provided an implicit reference conversion exists from B
to A
. 因為這些規則,當 reference_type 的陣列元素作為參考或輸出參數傳遞時,需要執行時間檢查,以確保陣列的實際專案類型與參數的實際元素類型相同。Because of these rules, when an array element of a reference_type is passed as a reference or output parameter, a run-time check is required to ensure that the actual element type of the array is identical to that of the parameter. 在範例中In the example
class Test
{
static void F(ref object x) {...}
static void Main() {
object[] a = new object[10];
object[] b = new string[10];
F(ref a[0]); // Ok
F(ref b[1]); // ArrayTypeMismatchException
}
}
的第二個調用會導致擲回, F
System.ArrayTypeMismatchException
因為的實際元素類型 b
是 string
,而不是 object
。the second invocation of F
causes a System.ArrayTypeMismatchException
to be thrown because the actual element type of b
is string
and not object
.
在展開的表單中叫用具有參數陣列的函式成員時,會完全依照陣列建立運算式(具有陣列初始化運算式的陣列建立運算式)來處理叫用 (陣列 建立運算式,) 在展開的參數周圍插入。When a function member with a parameter array is invoked in its expanded form, the invocation is processed exactly as if an array creation expression with an array initializer (Array creation expressions) was inserted around the expanded parameters. 例如,假設有宣告For example, given the declaration
void F(int x, int y, params object[] args);
下列擴充形式的方法調用:the following invocations of the expanded form of the method
F(10, 20);
F(10, 20, 30, 40);
F(10, 20, 1, "hello", 3.0);
完全對應至correspond exactly to
F(10, 20, new object[] {});
F(10, 20, new object[] {30, 40});
F(10, 20, new object[] {1, "hello", 3.0});
請特別注意,當針對參數陣列提供零個引數時,就會建立空的陣列。In particular, note that an empty array is created when there are zero arguments given for the parameter array.
使用對應的選擇性參數從函式成員省略引數時,會隱含地傳遞函數成員宣告的預設引數。When arguments are omitted from a function member with corresponding optional parameters, the default arguments of the function member declaration are implicitly passed. 因為這些一律是常數,所以其評估不會影響其餘引數的評估順序。Because these are always constant, their evaluation will not impact the evaluation order of the remaining arguments.
型別推斷Type inference
當呼叫泛型方法但未指定型別引數時, 型別推斷 進程會嘗試推斷呼叫的型別引數。When a generic method is called without specifying type arguments, a type inference process attempts to infer type arguments for the call. 型別推斷的存在,可讓您更方便地使用語法來呼叫泛型方法,並可讓程式設計人員避免指定多餘的型別資訊。The presence of type inference allows a more convenient syntax to be used for calling a generic method, and allows the programmer to avoid specifying redundant type information. 例如,假設有方法宣告:For example, given the method declaration:
class Chooser
{
static Random rand = new Random();
public static T Choose<T>(T first, T second) {
return (rand.Next(2) == 0)? first: second;
}
}
您可以叫 Choose
用方法,而不需要明確指定型別引數:it is possible to invoke the Choose
method without explicitly specifying a type argument:
int i = Chooser.Choose(5, 213); // Calls Choose<int>
string s = Chooser.Choose("foo", "bar"); // Calls Choose<string>
透過型別推斷,型別引數 int
string
是由方法的引數所決定。Through type inference, the type arguments int
and string
are determined from the arguments to the method.
型別推斷是做為方法調用之系結時間處理的一部分, (方法 調用) ,並在叫用的多載解析步驟之前進行。Type inference occurs as part of the binding-time processing of a method invocation (Method invocations) and takes place before the overload resolution step of the invocation. 在方法調用中指定特定方法群組,且未指定任何類型引數做為方法叫用的一部分時,會將型別推斷套用至方法群組中的每個泛型方法。When a particular method group is specified in a method invocation, and no type arguments are specified as part of the method invocation, type inference is applied to each generic method in the method group. 如果型別推斷成功,則會使用推斷的型別引數來決定後續多載解析的引數類型。If type inference succeeds, then the inferred type arguments are used to determine the types of arguments for subsequent overload resolution. 如果多載解析選擇泛型方法作為要叫用的方法,則會使用推斷的型別引數做為叫用的實際型別引數。If overload resolution chooses a generic method as the one to invoke, then the inferred type arguments are used as the actual type arguments for the invocation. 如果特定方法的型別推斷失敗,則該方法不會參與多載解析。If type inference for a particular method fails, that method does not participate in overload resolution. 型別推斷和本身的失敗不會造成系結階段錯誤。The failure of type inference, in and of itself, does not cause a binding-time error. 不過,當多載解析接著找不到任何適用的方法時,通常會導致發生系結階段錯誤。However, it often leads to a binding-time error when overload resolution then fails to find any applicable methods.
如果提供的引數數目與方法中的參數數目不同,則推斷會立即失敗。If the supplied number of arguments is different than the number of parameters in the method, then inference immediately fails. 否則,假設泛型方法具有下列簽章:Otherwise, assume that the generic method has the following signature:
Tr M<X1,...,Xn>(T1 x1, ..., Tm xm)
利用型別推斷的方法呼叫, M(E1...Em)
就是針對每個型別參數尋找唯一的型別引數, S1...Sn
X1...Xn
讓呼叫 M<S1...Sn>(E1...Em)
變成有效。With a method call of the form M(E1...Em)
the task of type inference is to find unique type arguments S1...Sn
for each of the type parameters X1...Xn
so that the call M<S1...Sn>(E1...Em)
becomes valid.
在推斷過程中,每個類型參數 Xi
都 固定 為特定類型, Si
或未使用相關聯的 界限 集進行固定。During the process of inference each type parameter Xi
is either fixed to a particular type Si
or unfixed with an associated set of bounds. 每個範圍都是一種類型 T
。Each of the bounds is some type T
. 一開始,每個類型變數 Xi
都會使用一組空的界限來固定。Initially each type variable Xi
is unfixed with an empty set of bounds.
型別推斷會以階段進行。Type inference takes place in phases. 每個階段都會根據上一個階段的結果,嘗試推斷更多類型變數的型別引數。Each phase will try to infer type arguments for more type variables based on the findings of the previous phase. 第一個階段會進行界限的一些初始推斷,而第二個階段則會將類型變數修正為特定類型,並推斷進一步的界限。The first phase makes some initial inferences of bounds, whereas the second phase fixes type variables to specific types and infers further bounds. 第二個階段可能必須重複數次。The second phase may have to be repeated a number of times.
注意: 只有在呼叫泛型方法時,才會發生型別推斷。Note: Type inference takes place not only when a generic method is called. 方法群組轉換的型別推斷會在 轉換方法群組的型別推斷 中描述,而尋找一組運算式的最佳一般型別,則會在 尋找一組運算式的最佳一般類型中描述。Type inference for conversion of method groups is described in Type inference for conversion of method groups and finding the best common type of a set of expressions is described in Finding the best common type of a set of expressions.
第一個階段The first phase
針對每個方法引數 Ei
:For each of the method arguments Ei
:
- 如果
Ei
是匿名函式,則 明確的參數類型推斷 (明確的參數類型推斷 ,)Ei
由Ti
IfEi
is an anonymous function, an explicit parameter type inference (Explicit parameter type inferences) is made fromEi
toTi
- 否則,如果的類型為,
Ei
U
且xi
為值參數,則會 從 進行 較低的 系結推斷U
Ti
。Otherwise, ifEi
has a typeU
andxi
is a value parameter then a lower-bound inference is made fromU
toTi
. - 否則,如果的
Ei
型別U
xi
是ref
或參數,out
則會 從 進行 確切的推斷U
Ti
。Otherwise, ifEi
has a typeU
andxi
is aref
orout
parameter then an exact inference is made fromU
toTi
. - 否則,就不會對此引數進行任何推斷。Otherwise, no inference is made for this argument.
第二個階段The second phase
第二個階段會繼續進行,如下所示:The second phase proceeds as follows:
- 所有不會相依于 (相依性) 的未 固定類型變數
Xi
Xj
, (修正) 。All unfixed type variablesXi
which do not depend on (Dependence) anyXj
are fixed (Fixing). - 如果沒有這 類型 別變數存在,則
Xi
會針對下列所有固定類型變數進行 修正 :If no such type variables exist, all unfixed type variablesXi
are fixed for which all of the following hold:- 至少有一個類型變數
Xj
相依于Xi
There is at least one type variableXj
that depends onXi
Xi
具有非空白的範圍集合Xi
has a non-empty set of bounds
- 至少有一個類型變數
- 如果沒有這類型別變數存在,但仍有未 固定 的型別變數,則類型推斷會失敗。If no such type variables exist and there are still unfixed type variables, type inference fails.
- 否則,如果沒有其他未 固定 的類型變數存在,則類型推斷會成功。Otherwise, if no further unfixed type variables exist, type inference succeeds.
- 否則,針對所有
Ei
具有對應參數類型的引數,其中輸出類型Ti
(輸出類型) 包含未處理的類型變數Xj
,但 輸入 類型 (輸入類型) 沒有,則會 從 進行輸出 型別推斷 (輸出型Ei
Ti
別推斷。Otherwise, for all argumentsEi
with corresponding parameter typeTi
where the output types (Output types) contain unfixed type variablesXj
but the input types (Input types) do not, an output type inference (Output type inferences) is made fromEi
toTi
. 接著會重複第二個階段。Then the second phase is repeated.
輸入類型Input types
如果 E
是方法群組或隱含型別匿名函式,而且 T
是委派型別或運算式樹狀結構型別,則的所有參數類型 T
都是類型為的 輸入類型 E
T
。If E
is a method group or implicitly typed anonymous function and T
is a delegate type or expression tree type then all the parameter types of T
are input types of E
with type T
.
輸出類型Output types
如果 E
是方法群組或匿名函式,而且 T
是委派型別或運算式樹狀結構型別,則的傳回型別 T
會是型 別的輸出型 別 E
T
。If E
is a method group or an anonymous function and T
is a delegate type or expression tree type then the return type of T
is an output type of E
with type T
.
依賴Dependence
未 固定 的型別變數 Xi
會 直接相依于 未固定的型別變數(如果針對具有類型的 Xj
輸入型別中的某些具有類型的引數 Ek
Tk
Xj
Ek
Tk
,且 Xi
發生于類型的 輸出類型 Ek
Tk
中)。An unfixed type variable Xi
depends directly on an unfixed type variable Xj
if for some argument Ek
with type Tk
Xj
occurs in an input type of Ek
with type Tk
and Xi
occurs in an output type of Ek
with type Tk
.
Xj
相依于 Xi
如果 Xj
直接相依 于 Xi
或, Xi
Xk
Xk
Xj
則取決於。Xj
depends on Xi
if Xj
depends directly on Xi
or if Xi
depends directly on Xk
and Xk
depends on Xj
. 因此,「相依于」是可轉移的,但不是「直接相依于」的自反項。Thus "depends on" is the transitive but not reflexive closure of "depends directly on".
輸出類型推斷Output type inferences
輸出型別推斷 會以下列方式 從 運算式建立 E
至 型別 T
:An output type inference is made from an expression E
to a type T
in the following way:
- 如果
E
是具有推斷傳回型別的匿名函式 (推斷的傳回型別U
) 而且T
是具有傳回型別的委派型別或運算式樹狀結構型別,則會向進行下限推斷Tb
() 下限推斷U
Tb
。IfE
is an anonymous function with inferred return typeU
(Inferred return type) andT
is a delegate type or expression tree type with return typeTb
, then a lower-bound inference (Lower-bound inferences) is made fromU
toTb
. - 否則,如果
E
是方法群組,且T
是具有參數類型和傳回類型的委派類型或運算式樹狀結構類型T1...Tk
Tb
,而且具有類型的多載解析會產生具有傳回類型的E
T1...Tk
單一方法U
,則會 從 進行 下限推斷U
Tb
。Otherwise, ifE
is a method group andT
is a delegate type or expression tree type with parameter typesT1...Tk
and return typeTb
, and overload resolution ofE
with the typesT1...Tk
yields a single method with return typeU
, then a lower-bound inference is made fromU
toTb
. - 否則,如果
E
是具有類型的運算式U
,則會 從 進行 較低的 系結推斷U
T
。Otherwise, ifE
is an expression with typeU
, then a lower-bound inference is made fromU
toT
. - 否則,就不會進行推斷。Otherwise, no inferences are made.
明確的參數類型推斷Explicit parameter type inferences
明確的參數類型推斷 會以下列方式 從 運算式建立 E
至 型別 T
:An explicit parameter type inference is made from an expression E
to a type T
in the following way:
- 如果
E
是具有參數類型的明確型別匿名函式U1...Uk
,而且T
是具有參數類型的委派類型或運算式樹狀結構類型,V1...Vk
則會對每個Ui
精確推斷 (精確推斷) 從Ui
對應的進行Vi
。IfE
is an explicitly typed anonymous function with parameter typesU1...Uk
andT
is a delegate type or expression tree type with parameter typesV1...Vk
then for eachUi
an exact inference (Exact inferences) is made fromUi
to the correspondingVi
.
確切推斷Exact inferences
從 類型到類型的 精確推斷 如下所示 U
V
:An exact inference from a type U
to a type V
is made as follows:
如果
V
是其中一個未 修復 的,則Xi
U
會新增至的確切界限集合Xi
。IfV
is one of the unfixedXi
thenU
is added to the set of exact bounds forXi
.否則,
V1...Vk
U1...Uk
會檢查是否有下列任何一種情況,以決定是否適用:Otherwise, setsV1...Vk
andU1...Uk
are determined by checking if any of the following cases apply:V
是陣列類型V1[...]
,而且U
是相同次序的陣列類型U1[...]
V
is an array typeV1[...]
andU
is an array typeU1[...]
of the same rankV
是型別V1?
,而且U
是型別U1?
V
is the typeV1?
andU
is the typeU1?
V
是一種結構化型別C<V1...Vk>
,而且U
是一種結構化的型別C<U1...Uk>
V
is a constructed typeC<V1...Vk>
andU
is a constructed typeC<U1...Uk>
如果有任何一種情況,則會 從 每個案例對對應的進行 精確推斷
Ui
Vi
。If any of these cases apply then an exact inference is made from eachUi
to the correspondingVi
.否則不會進行推斷。Otherwise no inferences are made.
下限推斷Lower-bound inferences
從 類型到類型的 下限推斷 如下所示 U
V
:A lower-bound inference from a type U
to a type V
is made as follows:
如果
V
是其中一個未 修復 的,則Xi
U
會新增至的下限集合Xi
。IfV
is one of the unfixedXi
thenU
is added to the set of lower bounds forXi
.否則,如果
V
是型別,V1?
而且是型別,則U
U1?
會從開始進行較低U1
V1
的系結推斷。Otherwise, ifV
is the typeV1?
andU
is the typeU1?
then a lower bound inference is made fromU1
toV1
.否則,
U1...Uk
V1...Vk
會檢查是否有下列任何一種情況,以決定是否適用:Otherwise, setsU1...Uk
andV1...Vk
are determined by checking if any of the following cases apply:V
是陣列型別V1[...]
,而且U
是陣列類型U1[...]
(或有效基底型別U1[...]
) 相同次序的型別參數V
is an array typeV1[...]
andU
is an array typeU1[...]
(or a type parameter whose effective base type isU1[...]
) of the same rankV
是、或的其中一IEnumerable<V1>
ICollection<V1>
IList<V1>
U
維陣列類型U1[]
(或有效基底類型為的類型參數U1[]
)V
is one ofIEnumerable<V1>
,ICollection<V1>
orIList<V1>
andU
is a one-dimensional array typeU1[]
(or a type parameter whose effective base type isU1[]
)V
是一種結構化的類別、結構、介面或委派型別C<V1...Vk>
,而且有一個唯一的型別,也就是C<U1...Uk>
U
(或者,如果U
是型別參數,則它的有效基類或其有效介面集的任何成員) 等同 (于直接或間接) ,或是直接或間接 ()C<U1...Uk>
。V
is a constructed class, struct, interface or delegate typeC<V1...Vk>
and there is a unique typeC<U1...Uk>
such thatU
(or, ifU
is a type parameter, its effective base class or any member of its effective interface set) is identical to, inherits from (directly or indirectly), or implements (directly or indirectly)C<U1...Uk>
.(「唯一性」限制表示在案例介面中
C<T> {} class U: C<X>, C<Y> {}
,從推斷時,不會進行任何推斷,U
C<T>
因為U1
可以是X
或Y
。 ) (The "uniqueness" restriction means that in the case interfaceC<T> {} class U: C<X>, C<Y> {}
, then no inference is made when inferring fromU
toC<T>
becauseU1
could beX
orY
.)
如果有上述任何一種情況,則會將 每個 案例的推斷進行對應,如下所示
Ui
Vi
:If any of these cases apply then an inference is made from eachUi
to the correspondingVi
as follows:- 如果
Ui
不知道是參考型別,則會進行 確切的推斷IfUi
is not known to be a reference type then an exact inference is made - 否則,如果
U
是陣列型別,則會進行 較低 系結的推斷Otherwise, ifU
is an array type then a lower-bound inference is made - 否則,如果
V
為,則C<V1...Vk>
推斷相依于的第 i 個型別參數C
:Otherwise, ifV
isC<V1...Vk>
then inference depends on the i-th type parameter ofC
:- 如果是協變數,則會進行 較低 系結的推斷。If it is covariant then a lower-bound inference is made.
- 如果是逆變的,則會進行 上限的推斷 。If it is contravariant then an upper-bound inference is made.
- 如果是不變的,則會進行 完全推斷 。If it is invariant then an exact inference is made.
否則,就不會進行推斷。Otherwise, no inferences are made.
上限推斷Upper-bound inferences
從 類型到類型的 上限推斷 U
V
會如下所示:An upper-bound inference from a type U
to a type V
is made as follows:
如果
V
是其中一個未 固定 的,則Xi
U
會新增至的上限集合Xi
。IfV
is one of the unfixedXi
thenU
is added to the set of upper bounds forXi
.否則,
V1...Vk
U1...Uk
會檢查是否有下列任何一種情況,以決定是否適用:Otherwise, setsV1...Vk
andU1...Uk
are determined by checking if any of the following cases apply:U
是陣列類型U1[...]
,而且V
是相同次序的陣列類型V1[...]
U
is an array typeU1[...]
andV
is an array typeV1[...]
of the same rankU
是IEnumerable<Ue>
、ICollection<Ue>
或以及一IList<Ue>
V
維陣列類型Ve[]
U
is one ofIEnumerable<Ue>
,ICollection<Ue>
orIList<Ue>
andV
is a one-dimensional array typeVe[]
U
是型別U1?
,而且V
是型別V1?
U
is the typeU1?
andV
is the typeV1?
U
是結構化類別、結構、介面或委派型別,C<U1...Uk>
而且V
是與相同的類別、結構、介面或委派型別,繼承自 (直接或間接) ,或是直接或間接) 唯一的型別來執行 (C<V1...Vk>
U
is constructed class, struct, interface or delegate typeC<U1...Uk>
andV
is a class, struct, interface or delegate type which is identical to, inherits from (directly or indirectly), or implements (directly or indirectly) a unique typeC<V1...Vk>
(「唯一性」限制表示如果有
interface C<T>{} class V<Z>: C<X<Z>>, C<Y<Z>>{}
,則在從推斷至時,不會進行任何C<U1>
推斷V<Q>
。(The "uniqueness" restriction means that if we haveinterface C<T>{} class V<Z>: C<X<Z>>, C<Y<Z>>{}
, then no inference is made when inferring fromC<U1>
toV<Q>
. 推斷並非由或組成U1
X<Q>
Y<Q>
。 ) Inferences are not made fromU1
to eitherX<Q>
orY<Q>
.)
如果有上述任何一種情況,則會將 每個 案例的推斷進行對應,如下所示
Ui
Vi
:If any of these cases apply then an inference is made from eachUi
to the correspondingVi
as follows:- 如果
Ui
不知道是參考型別,則會進行 確切的推斷IfUi
is not known to be a reference type then an exact inference is made - 否則,如果
V
是陣列型別,則會進行 上限的推斷Otherwise, ifV
is an array type then an upper-bound inference is made - 否則,如果
U
為,則C<U1...Uk>
推斷相依于的第 i 個型別參數C
:Otherwise, ifU
isC<U1...Uk>
then inference depends on the i-th type parameter ofC
:- 如果是協變數,則會進行 上限的推斷 。If it is covariant then an upper-bound inference is made.
- 如果是逆變的,則會進行 較低的推斷 。If it is contravariant then a lower-bound inference is made.
- 如果是不變的,則會進行 完全推斷 。If it is invariant then an exact inference is made.
否則,就不會進行推斷。Otherwise, no inferences are made.
修正Fixing
Xi
具有一組界限 的未 固定型別變數如下所示:An unfixed type variable Xi
with a set of bounds is fixed as follows:
- 一組 候選 型別會以一組
Uj
界限內的所有類型集合開始Xi
。The set of candidate typesUj
starts out as the set of all types in the set of bounds forXi
. - 接著,我們會逐一檢查每個系結,以
Xi
U
找出Xi
並非完全相同的所有型別,Uj
U
從候選集合中移除。We then examine each bound forXi
in turn: For each exact boundU
ofXi
all typesUj
which are not identical toU
are removed from the candidate set. 針對沒有U
Xi
隱含轉換的所有類型下限,Uj
U
會從候選集移除。For each lower boundU
ofXi
all typesUj
to which there is not an implicit conversion fromU
are removed from the candidate set. 針對U
Xi
所有沒有隱含轉換之類型的上限,Uj
U
都會從候選集移除。For each upper boundU
ofXi
all typesUj
from which there is not an implicit conversion toU
are removed from the candidate set. - 如果其餘的候選型別之間
Uj
有唯一的型別,則會V
隱含地轉換為所有其他候選型別,然後Xi
才會修正為V
。If among the remaining candidate typesUj
there is a unique typeV
from which there is an implicit conversion to all the other candidate types, thenXi
is fixed toV
. - 否則,型別推斷會失敗。Otherwise, type inference fails.
推斷的傳回型別Inferred return type
匿名函式的推斷傳回型別 F
會在型別推斷和多載解析期間使用。The inferred return type of an anonymous function F
is used during type inference and overload resolution. 推斷的傳回型別只能針對所有參數型別都是已知的匿名函式來決定,因為它們是明確指定的,透過匿名函式轉換提供,或在封閉式泛型方法調用的型別推斷期間推斷。The inferred return type can only be determined for an anonymous function where all parameter types are known, either because they are explicitly given, provided through an anonymous function conversion or inferred during type inference on an enclosing generic method invocation.
推斷的結果型 別會依照下列方式決定:The inferred result type is determined as follows:
- 如果的主體
F
是具有類型的 運算式 ,則推斷的結果型別F
是該運算式的型別。If the body ofF
is an expression that has a type, then the inferred result type ofF
is the type of that expression. - 如果的主體
F
是 區塊 ,且區塊語句中的一組運算式return
具有最佳的一般類型T
() 中 尋找一組運算式的最佳一般類型 ,則的推斷結果型別F
為T
。If the body ofF
is a block and the set of expressions in the block'sreturn
statements has a best common typeT
(Finding the best common type of a set of expressions), then the inferred result type ofF
isT
. - 否則,就無法推斷結果型別
F
。Otherwise, a result type cannot be inferred forF
.
推斷的傳回 型 別會依照下列方式決定:The inferred return type is determined as follows:
- 如果
F
是非同步,而且的主體F
是分類為 Nothing (運算式分類) 的運算式,或是沒有 return 語句有運算式的語句區塊,則推斷的傳回型別為System.Threading.Tasks.Task
IfF
is async and the body ofF
is either an expression classified as nothing (Expression classifications), or a statement block where no return statements have expressions, the inferred return type isSystem.Threading.Tasks.Task
- 如果
F
是非同步,而且具有推斷的結果型別T
,則推斷的傳回型別為System.Threading.Tasks.Task<T>
。IfF
is async and has an inferred result typeT
, the inferred return type isSystem.Threading.Tasks.Task<T>
. - 如果是非非同步,
F
而且具有推斷的結果型別T
,則推斷的傳回型別為T
。IfF
is non-async and has an inferred result typeT
, the inferred return type isT
. - 否則,就無法推斷傳回型別
F
。Otherwise a return type cannot be inferred forF
.
以匿名函式的型別推斷為例,請考慮在 Select
類別中宣告的擴充方法 System.Linq.Enumerable
:As an example of type inference involving anonymous functions, consider the Select
extension method declared in the System.Linq.Enumerable
class:
namespace System.Linq
{
public static class Enumerable
{
public static IEnumerable<TResult> Select<TSource,TResult>(
this IEnumerable<TSource> source,
Func<TSource,TResult> selector)
{
foreach (TSource element in source) yield return selector(element);
}
}
}
假設 System.Linq
使用子句匯入命名空間 using
,並指定 Customer
具有 Name
類型屬性的類別 string
,則 Select
可以使用方法來選取客戶清單的名稱:Assuming the System.Linq
namespace was imported with a using
clause, and given a class Customer
with a Name
property of type string
, the Select
method can be used to select the names of a list of customers:
List<Customer> customers = GetCustomerList();
IEnumerable<string> names = customers.Select(c => c.Name);
擴充方法調用 (擴充方法 調用) 的 Select
處理方式是將調用重寫為靜態方法調用:The extension method invocation (Extension method invocations) of Select
is processed by rewriting the invocation to a static method invocation:
IEnumerable<string> names = Enumerable.Select(customers, c => c.Name);
由於未明確指定類型引數,因此會使用型別推斷來推斷型別引數。Since type arguments were not explicitly specified, type inference is used to infer the type arguments. 首先, customers
引數與 source
參數相關,推斷 T
為 Customer
。First, the customers
argument is related to the source
parameter, inferring T
to be Customer
. 然後,使用上面所述的匿名函式類型推斷 c
程式,提供類型 Customer
,而運算式與 c.Name
參數的傳回型別 selector
(推斷為)相關 S
string
。Then, using the anonymous function type inference process described above, c
is given type Customer
, and the expression c.Name
is related to the return type of the selector
parameter, inferring S
to be string
. 因此,調用相當於Thus, the invocation is equivalent to
Sequence.Select<Customer,string>(customers, (Customer c) => c.Name)
而結果的型別為 IEnumerable<string>
。and the result is of type IEnumerable<string>
.
下列範例示範匿名函式型別推斷如何讓類型資訊在泛型方法調用中的引數之間進行「流程」。The following example demonstrates how anonymous function type inference allows type information to "flow" between arguments in a generic method invocation. 提供方法:Given the method:
static Z F<X,Y,Z>(X value, Func<X,Y> f1, Func<Y,Z> f2) {
return f2(f1(value));
}
調用的型別推斷:Type inference for the invocation:
double seconds = F("1:15:30", s => TimeSpan.Parse(s), t => t.TotalSeconds);
繼續進行,如下所示:首先,引數 "1:15:30"
與 value
參數相關,推斷 X
為 string
。proceeds as follows: First, the argument "1:15:30"
is related to the value
parameter, inferring X
to be string
. 然後,會為第一個匿名函式的參數 s
指定推斷型別 string
,而且運算式會與 TimeSpan.Parse(s)
的傳回型別 f1
(推斷為)相關聯 Y
System.TimeSpan
。Then, the parameter of the first anonymous function, s
, is given the inferred type string
, and the expression TimeSpan.Parse(s)
is related to the return type of f1
, inferring Y
to be System.TimeSpan
. 最後,第二個匿名函式的參數 t
會獲得推斷型別 System.TimeSpan
,而且運算式與 t.TotalSeconds
的傳回型別 f2
(推斷為)相關 Z
double
。Finally, the parameter of the second anonymous function, t
, is given the inferred type System.TimeSpan
, and the expression t.TotalSeconds
is related to the return type of f2
, inferring Z
to be double
. 因此,調用的結果是類型 double
。Thus, the result of the invocation is of type double
.
方法群組轉換的型別推斷Type inference for conversion of method groups
類似于泛型方法的呼叫,當 M
包含泛型方法的方法群組轉換成指定的委派類型 D
(方法群組轉換) 時,也必須套用型別推斷。Similar to calls of generic methods, type inference must also be applied when a method group M
containing a generic method is converted to a given delegate type D
(Method group conversions). 指定方法Given a method
Tr M<X1...Xn>(T1 x1 ... Tm xm)
而且要 M
指派給委派類型的方法群組, D
推斷類型的工作就是尋找型別引數, S1...Sn
讓運算式:and the method group M
being assigned to the delegate type D
the task of type inference is to find type arguments S1...Sn
so that the expression:
M<S1...Sn>
會變成與) 的 (委派 宣告相容 D
。becomes compatible (Delegate declarations) with D
.
不同于泛型方法呼叫的型別推斷演算法,在此案例中,只有引數 類型,沒有引數 運算式。Unlike the type inference algorithm for generic method calls, in this case there are only argument types, no argument expressions. 尤其是,沒有任何匿名函式,因此不需要多個推斷階段。In particular, there are no anonymous functions and hence no need for multiple phases of inference.
相反地,所有的 Xi
都會被視為未 固定 的,而 從 的每個引數類型到的對應參數類型都會進行 較低的 系結推斷 Uj
D
Tj
M
。Instead, all Xi
are considered unfixed, and a lower-bound inference is made from each argument type Uj
of D
to the corresponding parameter type Tj
of M
. 如果找不到任何 Xi
界限的,則類型推斷會失敗。If for any of the Xi
no bounds were found, type inference fails. 否則,所有的 Xi
都會 修正 為對應的 Si
,這是型別推斷的結果。Otherwise, all Xi
are fixed to corresponding Si
, which are the result of type inference.
尋找一組運算式的最佳一般類型Finding the best common type of a set of expressions
在某些情況下,必須針對一組運算式推斷一般類型。In some cases, a common type needs to be inferred for a set of expressions. 尤其是,隱含類型陣列的專案類型,以及具有 區塊 主體之匿名函式的傳回型別,都會以這種方式找到。In particular, the element types of implicitly typed arrays and the return types of anonymous functions with block bodies are found in this way.
以直覺方式,假設有一組運算式, E1...Em
則此推斷應等同于呼叫方法Intuitively, given a set of expressions E1...Em
this inference should be equivalent to calling a method
Tr M<X>(X x1 ... X xm)
with Ei
做為引數。with the Ei
as arguments.
更精確地說,推斷是從未 固定 的型別變數開始 X
。More precisely, the inference starts out with an unfixed type variable X
. 然後,會 從 每個產生 輸出型別推斷 Ei
X
。Output type inferences are then made from each Ei
to X
. 最後, X
是 固定 的,而且如果成功,則產生的型別 S
是運算式所產生的最佳一般型別。Finally, X
is fixed and, if successful, the resulting type S
is the resulting best common type for the expressions. 如果不 S
存在,則運算式沒有最佳的一般類型。If no such S
exists, the expressions have no best common type.
多載解析Overload resolution
多載解析是一種系結時間機制,可在指定引數清單和一組候選函數成員的情況之下,選取最佳的函式成員來叫用。Overload resolution is a binding-time mechanism for selecting the best function member to invoke given an argument list and a set of candidate function members. 多載解析會選取要在 c # 中的下列不同內容中叫用的函式成員:Overload resolution selects the function member to invoke in the following distinct contexts within C#:
- Invocation_expression (方法調用中名為的方法調用) 。Invocation of a method named in an invocation_expression (Method invocations).
- ) object_creation_expression (物件建立運算式 中所命名的實例函式調用。Invocation of an instance constructor named in an object_creation_expression (Object creation expressions).
- 透過 element_access (專案 存取) 來調用索引子存取子。Invocation of an indexer accessor through an element_access (Element access).
- 運算式中所參考之預先定義或使用者定義運算子的調用 (一元運算子 多載解析和 二元運算子 多載解析) 。Invocation of a predefined or user-defined operator referenced in an expression (Unary operator overload resolution and Binary operator overload resolution).
上述每個內容都會以各自獨特的方式定義一組候選函式成員和引數清單,如上面所列各節中的詳細說明。Each of these contexts defines the set of candidate function members and the list of arguments in its own unique way, as described in detail in the sections listed above. 例如,方法調用的候選集合不包含標示 override
(成員查閱) 的方法,而且如果衍生類別中的任何方法適用 (方法調用) ,則基類中的方法不是候選項目。For example, the set of candidates for a method invocation does not include methods marked override
(Member lookup), and methods in a base class are not candidates if any method in a derived class is applicable (Method invocations).
一旦識別出候選函式成員和引數清單之後,在所有情況下,最佳函式成員的選取都會相同:Once the candidate function members and the argument list have been identified, the selection of the best function member is the same in all cases:
- 假設有一組適用的候選函式成員,就會找到該集合中的最佳函數成員。Given the set of applicable candidate function members, the best function member in that set is located. 如果集合中只有一個函式成員,則該函數成員是最佳的函式成員。If the set contains only one function member, then that function member is the best function member. 否則,最好的函式成員就是一個函數成員,比起指定引數清單的所有其他函式成員更好,前提是每個函式成員都是使用 更好的函式成員中的規則來與所有其他函式成員進行比較。Otherwise, the best function member is the one function member that is better than all other function members with respect to the given argument list, provided that each function member is compared to all other function members using the rules in Better function member. 如果沒有正好一個比所有其他函式成員更好的函式成員,則函數成員調用會不明確,而且會發生系結階段錯誤。If there is not exactly one function member that is better than all other function members, then the function member invocation is ambiguous and a binding-time error occurs.
下列章節定義詞彙 * 適用的函式 成員 _ 和 _ *更好 的函式成員 * * 的確切意義。The following sections define the exact meanings of the terms applicable function member _ and _better function member**.
適用的函數成員Applicable function member
當下列所有條件都成立時,就會將函式成員視為與引數清單相關的 函數成員 A
:A function member is said to be an applicable function member with respect to an argument list A
when all of the following are true:
- 中的每個引數
A
會對應至函式成員宣告中的參數(如 對應的參數中所述),而且沒有任何引數對應的任何參數都是選擇性參數。Each argument inA
corresponds to a parameter in the function member declaration as described in Corresponding parameters, and any parameter to which no argument corresponds is an optional parameter. - 針對中的每個引數
A
,引數的參數傳遞模式 (例如、值、ref
或out
) 等同于對應參數的參數傳遞模式,以及For each argument inA
, the parameter passing mode of the argument (i.e., value,ref
, orout
) is identical to the parameter passing mode of the corresponding parameter, and- 如果是值參數或參數陣列, (隱含 轉換) 存在於對應參數類型的引數中,或for a value parameter or a parameter array, an implicit conversion (Implicit conversions) exists from the argument to the type of the corresponding parameter, or
- 針對
ref
或out
參數,引數的類型與對應參數的類型相同。for aref
orout
parameter, the type of the argument is identical to the type of the corresponding parameter. 畢竟,ref
或out
參數是傳遞引數的別名。After all, aref
orout
parameter is an alias for the argument passed.
針對包含參數陣列的函式成員,如果函式成員適用于上述規則,則會被視為適用于其 *標準格式 _。For a function member that includes a parameter array, if the function member is applicable by the above rules, it is said to be applicable in its *normal form _. 如果包含參數陣列的函式成員不是適用于其一般格式,則函式成員可能會改為適用于其 _ 展開的表單 *:If a function member that includes a parameter array is not applicable in its normal form, the function member may instead be applicable in its _*expanded form**:
- 展開的表單的建立方式,是將函數成員宣告中的參數陣列取代為參數陣列元素類型的零或多個值參數,讓引數清單中的引數數目
A
符合參數的總數目。The expanded form is constructed by replacing the parameter array in the function member declaration with zero or more value parameters of the element type of the parameter array such that the number of arguments in the argument listA
matches the total number of parameters. 如果A
引數的引數數目少於函數成員宣告中的固定參數數目,則無法建立函式成員的擴充形式,因此不適用。IfA
has fewer arguments than the number of fixed parameters in the function member declaration, the expanded form of the function member cannot be constructed and is thus not applicable. - 否則,如果對
A
引數的參數傳遞模式中的每個引數,都與對應參數的參數傳遞模式相同,則會適用展開的表單,而且Otherwise, the expanded form is applicable if for each argument inA
the parameter passing mode of the argument is identical to the parameter passing mode of the corresponding parameter, and- 若為固定值參數或展開所建立的值參數,隱含轉換 (隱含 轉換) 存在於引數的類型與對應參數的類型,或for a fixed value parameter or a value parameter created by the expansion, an implicit conversion (Implicit conversions) exists from the type of the argument to the type of the corresponding parameter, or
- 針對
ref
或out
參數,引數的類型與對應參數的類型相同。for aref
orout
parameter, the type of the argument is identical to the type of the corresponding parameter.
更好的函式成員Better function member
為了決定更好的函式成員,移除引數清單 A 會以其在原始引數清單中出現的順序,直接包含引數運算式本身。For the purposes of determining the better function member, a stripped-down argument list A is constructed containing just the argument expressions themselves in the order they appear in the original argument list.
每個候選函數成員的參數清單會以下列方式建立:Parameter lists for each of the candidate function members are constructed in the following way:
- 如果函數成員僅適用于展開的表單,則會使用展開的表單。The expanded form is used if the function member was applicable only in the expanded form.
- 未對應引數的選擇性參數會從參數清單中移除Optional parameters with no corresponding arguments are removed from the parameter list
- 這些參數會重新排序,使其出現在引數清單中與對應引數相同的位置。The parameters are reordered so that they occur at the same position as the corresponding argument in the argument list.
假設有一個引數清單 A
包含一組引數運算式 {E1, E2, ..., En}
,以及兩個適用的函式成員 Mp
和 Mq
參數類型 {P1, P2, ..., Pn}
和 {Q1, Q2, ..., Qn}
, Mp
則定義為比 if 更好 的 Mq
函式成員Given an argument list A
with a set of argument expressions {E1, E2, ..., En}
and two applicable function members Mp
and Mq
with parameter types {P1, P2, ..., Pn}
and {Q1, Q2, ..., Qn}
, Mp
is defined to be a better function member than Mq
if
- 針對每個引數,從到到的隱含轉換
Ex
Qx
不優於從轉換成的隱含轉換Ex
Px
,以及for each argument, the implicit conversion fromEx
toQx
is not better than the implicit conversion fromEx
toPx
, and - 若至少有一個引數,從轉換
Ex
成Px
優於從轉換為Ex
Qx
。for at least one argument, the conversion fromEx
toPx
is better than the conversion fromEx
toQx
.
執行這項評估時,如果 Mp
或 Mq
適用于其展開的表單,則為, Px
或 Qx
參考參數清單的擴充形式中的參數。When performing this evaluation, if Mp
or Mq
is applicable in its expanded form, then Px
or Qx
refers to a parameter in the expanded form of the parameter list.
如果參數類型順序 {P1, P2, ..., Pn}
和 {Q1, Q2, ..., Qn}
相等 (也就是每個都 Pi
有對應) 的身分識別轉換 Qi
,則會依序套用下列系結規則,以判斷更好的函數成員。In case the parameter type sequences {P1, P2, ..., Pn}
and {Q1, Q2, ..., Qn}
are equivalent (i.e. each Pi
has an identity conversion to the corresponding Qi
), the following tie-breaking rules are applied, in order, to determine the better function member.
- 如果是非
Mp
泛型方法且Mq
為泛型方法,則Mp
比更好Mq
。IfMp
is a non-generic method andMq
is a generic method, thenMp
is better thanMq
. - 否則,如果
Mp
適用于其一般形式且Mq
具有陣列,params
且僅適用于其展開的表單,則Mp
比更好Mq
。Otherwise, ifMp
is applicable in its normal form andMq
has aparams
array and is applicable only in its expanded form, thenMp
is better thanMq
. - 否則,如果
Mp
的宣告參數多於Mq
,則Mp
比更好Mq
。Otherwise, ifMp
has more declared parameters thanMq
, thenMp
is better thanMq
. 如果這兩個方法都具有params
陣列,且僅適用于其展開的表單,就會發生這種情況。This can occur if both methods haveparams
arrays and are applicable only in their expanded forms. - 否則,如果的所有參數
Mp
都有對應的引數,而預設引數必須在中至少替代一個選擇性參數,則Mq
Mp
比更好Mq
。Otherwise if all parameters ofMp
have a corresponding argument whereas default arguments need to be substituted for at least one optional parameter inMq
thenMp
is better thanMq
. - 否則,如果
Mp
有比更多的特定參數類型Mq
,則Mp
比更好Mq
。Otherwise, ifMp
has more specific parameter types thanMq
, thenMp
is better thanMq
. 讓和表示和的未具現化{R1, R2, ..., Rn}
{S1, S2, ..., Sn}
和未展開參數類型Mp
Mq
。Let{R1, R2, ..., Rn}
and{S1, S2, ..., Sn}
represent the uninstantiated and unexpanded parameter types ofMp
andMq
.Mp
的參數類型比起的更為明確,Mq
如果每個參數的Rx
特定比更不明確,Sx
而且至少要有一個參數,Rx
則更明確Sx
地表示:Mp
's parameter types are more specific thanMq
's if, for each parameter,Rx
is not less specific thanSx
, and, for at least one parameter,Rx
is more specific thanSx
:- 類型參數比非類型參數更不特定。A type parameter is less specific than a non-type parameter.
- 以遞迴方式來說,如果至少有一個型別引數是更特定的類型引數,而且沒有任何類型引數比另一個類型引數更明確,則結構化型別會比另一個具有相同類型) 引數的型別引數 (更明確。Recursively, a constructed type is more specific than another constructed type (with the same number of type arguments) if at least one type argument is more specific and no type argument is less specific than the corresponding type argument in the other.
- 陣列類型比其他陣列類型更明確 (具有相同維度數目的陣列) 如果第一個的元素類型比第二個專案類型更明確。An array type is more specific than another array type (with the same number of dimensions) if the element type of the first is more specific than the element type of the second.
- 否則,如果其中一個成員是非提起運算子,另一個成員是一個帶向的運算子,則未提升的運算子比較好。Otherwise if one member is a non-lifted operator and the other is a lifted operator, the non-lifted one is better.
- 否則,這兩個函數成員都不是比較好的做法。Otherwise, neither function member is better.
從運算式進行更好的轉換Better conversion from expression
假設 C1
從運算式轉換成類型的隱含轉換 E
T1
,以及 C2
從運算式轉換成類型的隱含轉換, E
T2
C1
則會比 C2
E
不完全相符, T2
而且至少有下列其中一個保留的轉換更好:Given an implicit conversion C1
that converts from an expression E
to a type T1
, and an implicit conversion C2
that converts from an expression E
to a type T2
, C1
is a better conversion than C2
if E
does not exactly match T2
and at least one of the following holds:
E
完全符合T1
(完全 相符的運算式)E
exactly matchesT1
(Exactly matching Expression)T1
比T2
(更好的轉換目標)T1
is a better conversion target thanT2
(Better conversion target)
完全相符的運算式Exactly matching Expression
假設有一個運算式 E
和一個型別 T
, E
T
如果下列其中一項保存,就完全相符:Given an expression E
and a type T
, E
exactly matches T
if one of the following holds:
E
有型別S
,而身分識別轉換存在S
于T
E
has a typeS
, and an identity conversion exists fromS
toT
E
是匿名函式,T
它可以是委派型別,也可以是D
運算式樹狀架構型別,Expression<D>
以及下列其中一個保存:E
is an anonymous function,T
is either a delegate typeD
or an expression tree typeExpression<D>
and one of the following holds:X
E
在 (推斷的傳回型別) 的參數清單內容中,有一個推斷的傳回型別存在D
,而且會從傳回型別轉換X
為D
An inferred return typeX
exists forE
in the context of the parameter list ofD
(Inferred return type), and an identity conversion exists fromX
to the return type ofD
- 可能
E
是非非同步,且D
具有傳回型別Y
或E
非同步且D
具有傳回型別Task<Y>
,而且有下列其中一項保留:EitherE
is non-async andD
has a return typeY
orE
is async andD
has a return typeTask<Y>
, and one of the following holds:- 的主體
E
是完全符合的運算式Y
The body ofE
is an expression that exactly matchesY
- 的主體
E
是語句區塊,其中每個 return 語句會傳回完全相符的運算式Y
The body ofE
is a statement block where every return statement returns an expression that exactly matchesY
- 的主體
更好的轉換目標Better conversion target
假設有兩種不同的類型 T1
和 T2
, T1
則比起 T2
從隱含轉換成不 T2
T1
存在,以及至少下列其中一個保留的目標是較佳的轉換目標:Given two different types T1
and T2
, T1
is a better conversion target than T2
if no implicit conversion from T2
to T1
exists, and at least one of the following holds:
- 從隱含轉換
T1
成T2
existsAn implicit conversion fromT1
toT2
exists T1
是委派類型D1
或運算式樹狀架構類型Expression<D1>
,T2
是委派類型D2
或運算式樹狀結構類型Expression<D2>
,D1
具有傳回類型S1
和下列其中一個保留:T1
is either a delegate typeD1
or an expression tree typeExpression<D1>
,T2
is either a delegate typeD2
or an expression tree typeExpression<D2>
,D1
has a return typeS1
and one of the following holds:D2
傳回 voidD2
is void returningD2
具有傳回型別S2
,而且S1
比起的轉換目標更好S2
D2
has a return typeS2
, andS1
is a better conversion target thanS2
T1
是Task<S1>
,T2
是Task<S2>
,而且S1
比起的轉換目標更好S2
T1
isTask<S1>
,T2
isTask<S2>
, andS1
is a better conversion target thanS2
T1
是S1
或,S1?
其中S1
是帶正負號的整數類資料類型,而T2
是S2
或S2?
S2
不帶正負號的整數類型。T1
isS1
orS1?
whereS1
is a signed integral type, andT2
isS2
orS2?
whereS2
is an unsigned integral type. 具體來說:Specifically:S1
為sbyte
S2
,且為byte
、ushort
、uint
或ulong
S1
issbyte
andS2
isbyte
,ushort
,uint
, orulong
S1
為short
S2
,且為ushort
、uint
或。ulong
S1
isshort
andS2
isushort
,uint
, orulong
S1
為int
S2
,且為uint
、或。ulong
S1
isint
andS2
isuint
, orulong
S1
為long
,且S2
為ulong
S1
islong
andS2
isulong
泛型類別中的多載Overloading in generic classes
雖然宣告的簽章必須是唯一的,但類型引數的替代可能會產生相同的簽章。While signatures as declared must be unique, it is possible that substitution of type arguments results in identical signatures. 在這種情況下,上述多載解析的系結規則將挑選最特定的成員。In such cases, the tie-breaking rules of overload resolution above will pick the most specific member.
下列範例會根據此規則顯示有效且不正確多載:The following examples show overloads that are valid and invalid according to this rule:
interface I1<T> {...}
interface I2<T> {...}
class G1<U>
{
int F1(U u); // Overload resolution for G<int>.F1
int F1(int i); // will pick non-generic
void F2(I1<U> a); // Valid overload
void F2(I2<U> a);
}
class G2<U,V>
{
void F3(U u, V v); // Valid, but overload resolution for
void F3(V v, U u); // G2<int,int>.F3 will fail
void F4(U u, I1<V> v); // Valid, but overload resolution for
void F4(I1<V> v, U u); // G2<I1<int>,int>.F4 will fail
void F5(U u1, I1<V> v2); // Valid overload
void F5(V v1, U u2);
void F6(ref U u); // valid overload
void F6(out V v);
}
動態多載解析的編譯時間檢查Compile-time checking of dynamic overload resolution
針對大部分動態系結的作業,可能會在編譯時期未知的解析候選項目集合。For most dynamically bound operations the set of possible candidates for resolution is unknown at compile-time. 但是在某些情況下,候選集在編譯時期是已知的:In certain cases, however the candidate set is known at compile-time:
- 使用動態引數的靜態方法呼叫Static method calls with dynamic arguments
- 接收者不是動態運算式的實例方法呼叫Instance method calls where the receiver is not a dynamic expression
- 接收器不是動態運算式的索引子呼叫Indexer calls where the receiver is not a dynamic expression
- 使用動態引數的函式呼叫Constructor calls with dynamic arguments
在這些情況下,會針對每個候選項目執行有限的編譯時間檢查,以查看是否有任何可能在執行時間套用。這項檢查是由下列步驟所組成:In these cases a limited compile-time check is performed for each candidate to see if any of them could possibly apply at run-time.This check consists of the following steps:
- 部分類型推斷:不直接或間接相依于型別引數的任何類型引數,
dynamic
都會使用 型別推斷的規則來推斷。Partial type inference: Any type argument that does not depend directly or indirectly on an argument of typedynamic
is inferred using the rules of Type inference. 其餘的類型引數未知。The remaining type arguments are unknown. - 部分適用性檢查:根據適用的函式 成員檢查適用性,但忽略類型未知的參數。Partial applicability check: Applicability is checked according to Applicable function member, but ignoring parameters whose types are unknown.
- 如果沒有候選項通過這項測試,就會發生編譯時期錯誤。If no candidate passes this test, a compile-time error occurs.
函數成員調用Function member invocation
本節說明在執行時間發生的程式,以叫用特定的函式成員。This section describes the process that takes place at run-time to invoke a particular function member. 假設系結時間進程已經決定要叫用的特定成員,可能的方法是將多載解析套用至一組候選函數成員。It is assumed that a binding-time process has already determined the particular member to invoke, possibly by applying overload resolution to a set of candidate function members.
為了描述調用程式,函式成員分為兩類:For purposes of describing the invocation process, function members are divided into two categories:
- 靜態函數成員。Static function members. 這些是實例的函式、靜態方法、靜態屬性存取子,以及使用者定義的運算子。These are instance constructors, static methods, static property accessors, and user-defined operators. 靜態函數成員一律為非虛擬。Static function members are always non-virtual.
- 實例函數成員。Instance function members. 這些是實例方法、實例屬性存取子和索引子存取子。These are instance methods, instance property accessors, and indexer accessors. 實例函數成員為非虛擬或虛擬的,而且一律會在特定的實例上叫用。Instance function members are either non-virtual or virtual, and are always invoked on a particular instance. 實例運算式會計算實例,而且它會在函式成員內變成可存取,
this
(此存取) 。The instance is computed by an instance expression, and it becomes accessible within the function member asthis
(This access).
函數成員調用的執行時間處理包含下列步驟,其中 M
是函數成員,而如果 M
是實例成員, E
則是實例運算式:The run-time processing of a function member invocation consists of the following steps, where M
is the function member and, if M
is an instance member, E
is the instance expression:
如果
M
是靜態函數成員:IfM
is a static function member:- 引數清單中會評估 引數清單中所述的引數清單。The argument list is evaluated as described in Argument lists.
- 叫用
M
。M
is invoked.
如果
M
是在 value_type 中宣告的實例函數成員:IfM
is an instance function member declared in a value_type:E
會進行評估。E
is evaluated. 如果此評估造成例外狀況,則不會執行任何進一步的步驟。If this evaluation causes an exception, then no further steps are executed.- 如果未
E
分類為變數,則會建立型別的暫存區域變數,E
並將的值指派給E
該變數。IfE
is not classified as a variable, then a temporary local variable ofE
's type is created and the value ofE
is assigned to that variable.E
然後重新分類為該暫存區域變數的參考。E
is then reclassified as a reference to that temporary local variable. 暫時變數可以像內部存取this
M
,但無法以任何其他方式存取。The temporary variable is accessible asthis
withinM
, but not in any other way. 因此,只有在E
是真正的變數時,呼叫端才能觀察到所進行的變更M
this
。Thus, only whenE
is a true variable is it possible for the caller to observe the changes thatM
makes tothis
. - 引數清單中會評估 引數清單中所述的引數清單。The argument list is evaluated as described in Argument lists.
- 叫用
M
。M
is invoked. 所參考的變數E
會成為所參考的this
變數。The variable referenced byE
becomes the variable referenced bythis
.
如果
M
是在 reference_type 中宣告的實例函數成員:IfM
is an instance function member declared in a reference_type:E
會進行評估。E
is evaluated. 如果此評估造成例外狀況,則不會執行任何進一步的步驟。If this evaluation causes an exception, then no further steps are executed.- 引數清單中會評估 引數清單中所述的引數清單。The argument list is evaluated as described in Argument lists.
- 如果的型別
E
是 value_type,則會執行) 的裝箱轉換 (將轉換轉換E
成型別object
,而且E
會被視為object
在下列步驟中的型別。If the type ofE
is a value_type, a boxing conversion (Boxing conversions) is performed to convertE
to typeobject
, andE
is considered to be of typeobject
in the following steps. 在此情況下,M
只能是的成員System.Object
。In this case,M
could only be a member ofSystem.Object
. - 的值
E
會被檢查為有效。The value ofE
is checked to be valid. 如果的值E
為null
,則會擲回,System.NullReferenceException
且不會執行任何進一步的步驟。If the value ofE
isnull
, aSystem.NullReferenceException
is thrown and no further steps are executed. - 將會決定要叫用的函式成員實作為:The function member implementation to invoke is determined:
- 如果的系結時間型別是介面,則叫用的函
E
式成員是由所M
參考之實例的執行時間型別所提供的實作為E
。If the binding-time type ofE
is an interface, the function member to invoke is the implementation ofM
provided by the run-time type of the instance referenced byE
. 這個函式成員是藉由將介面對應規則套用 (介面) 對應 來決定,以判斷由所M
參考之實例的執行時間型別所提供的實作為E
。This function member is determined by applying the interface mapping rules (Interface mapping) to determine the implementation ofM
provided by the run-time type of the instance referenced byE
. - 否則,如果是虛擬函式成員,則叫用的函
M
式成員是M
由所參考之實例的執行時間型別所提供的實作為E
。Otherwise, ifM
is a virtual function member, the function member to invoke is the implementation ofM
provided by the run-time type of the instance referenced byE
. 這個函式成員是藉由套用規則來決定最 (的 虛擬方法) 的虛擬方法M
,而這是與所參考之實例的執行時間型別有關E
。This function member is determined by applying the rules for determining the most derived implementation (Virtual methods) ofM
with respect to the run-time type of the instance referenced byE
. - 否則,是非
M
虛擬函式成員,而叫用的函式成員本身就是M
。Otherwise,M
is a non-virtual function member, and the function member to invoke isM
itself.
- 如果的系結時間型別是介面,則叫用的函
- 叫用上述步驟中所決定的函式成員執行。The function member implementation determined in the step above is invoked. 所參考的物件
E
會成為所參考的this
物件。The object referenced byE
becomes the object referenced bythis
.
對盒裝實例的調用Invocations on boxed instances
在下列情況下,可以透過 value_type 的已封裝實例叫用在 value_type 中執行的函式成員:A function member implemented in a value_type can be invoked through a boxed instance of that value_type in the following situations:
- 當函數成員是
override
繼承自型別的方法時object
,會透過型別的實例運算式叫用object
。When the function member is anoverride
of a method inherited from typeobject
and is invoked through an instance expression of typeobject
. - 當函式成員是介面函式成員的執行時,會透過 interface_type 的實例運算式叫用。When the function member is an implementation of an interface function member and is invoked through an instance expression of an interface_type.
- 當函數成員透過委派叫用時。When the function member is invoked through a delegate.
在這些情況下,會將盒裝實例視為包含 value_type 的變數,而這個變數會成為函式成員調用內所參考的變數 this
。In these situations, the boxed instance is considered to contain a variable of the value_type, and this variable becomes the variable referenced by this
within the function member invocation. 特別是,這表示在已封裝的實例上叫用函式成員時,函式成員可能會修改包含在已加入的實例中的值。In particular, this means that when a function member is invoked on a boxed instance, it is possible for the function member to modify the value contained in the boxed instance.
主要運算式Primary expressions
主要運算式包括最簡單的運算式形式。Primary expressions include the simplest forms of expressions.
primary_expression
: primary_no_array_creation_expression
| array_creation_expression
;
primary_no_array_creation_expression
: literal
| interpolated_string_expression
| simple_name
| parenthesized_expression
| member_access
| invocation_expression
| element_access
| this_access
| base_access
| post_increment_expression
| post_decrement_expression
| object_creation_expression
| delegate_creation_expression
| anonymous_object_creation_expression
| typeof_expression
| checked_expression
| unchecked_expression
| default_value_expression
| nameof_expression
| anonymous_method_expression
| primary_no_array_creation_expression_unsafe
;
主要運算式 array_creation_expression s 和 primary_no_array_creation_expression 之間劃分。Primary expressions are divided between array_creation_expression s and primary_no_array_creation_expression s. 以這種方式來處理陣列建立運算式,而不是與其他簡單的運算式表單一起列出,可讓文法不允許可能令人困惑的程式碼,例如Treating array-creation-expression in this way, rather than listing it along with the other simple expression forms, enables the grammar to disallow potentially confusing code such as
object o = new int[3][1];
否則會解釋為which would otherwise be interpreted as
object o = (new int[3])[1];
常值Literals
Primary_expression ,其中包含 常 值 (常值) 分類為值。A primary_expression that consists of a literal (Literals) is classified as a value.
插入字串Interpolated strings
Interpolated_string_expression 是由 $
後面接著一般或逐字字串常值的正負號所組成,其中的洞以 {
和分隔,以 }
括住運算式和格式化規格。An interpolated_string_expression consists of a $
sign followed by a regular or verbatim string literal, wherein holes, delimited by {
and }
, enclose expressions and formatting specifications. 插入字串運算式是已細分為個別標記的 interpolated_string_literal 結果,如插入 字串常值中所述。An interpolated string expression is the result of an interpolated_string_literal that has been broken up into individual tokens, as described in Interpolated string literals.
interpolated_string_expression
: '$' interpolated_regular_string
| '$' interpolated_verbatim_string
;
interpolated_regular_string
: interpolated_regular_string_whole
| interpolated_regular_string_start interpolated_regular_string_body interpolated_regular_string_end
;
interpolated_regular_string_body
: interpolation (interpolated_regular_string_mid interpolation)*
;
interpolation
: expression
| expression ',' constant_expression
;
interpolated_verbatim_string
: interpolated_verbatim_string_whole
| interpolated_verbatim_string_start interpolated_verbatim_string_body interpolated_verbatim_string_end
;
interpolated_verbatim_string_body
: interpolation (interpolated_verbatim_string_mid interpolation)+
;
插補中的 constant_expression 必須隱含轉換成 int
。The constant_expression in an interpolation must have an implicit conversion to int
.
Interpolated_string_expression 分類為值。An interpolated_string_expression is classified as a value. 如果它立即轉換成 System.IFormattable
或 System.FormattableString
使用隱含的插入字串轉換 (隱含 插入字串轉換) ,則插入字串運算式具有該類型。If it is immediately converted to System.IFormattable
or System.FormattableString
with an implicit interpolated string conversion (Implicit interpolated string conversions), the interpolated string expression has that type. 否則,它會有型別 string
。Otherwise, it has the type string
.
如果內插字串的類型是 System.IFormattable
或 System.FormattableString
,則意義是的呼叫 System.Runtime.CompilerServices.FormattableStringFactory.Create
。If the type of an interpolated string is System.IFormattable
or System.FormattableString
, the meaning is a call to System.Runtime.CompilerServices.FormattableStringFactory.Create
. 如果類型為 string
,則運算式的意義是的呼叫 string.Format
。If the type is string
, the meaning of the expression is a call to string.Format
. 在這兩種情況下,呼叫的引數清單都包含格式字串常值,其中包含每個插補的預留位置,以及對應至預留位置的每個運算式的引數。In both cases, the argument list of the call consists of a format string literal with placeholders for each interpolation, and an argument for each expression corresponding to the place holders.
格式字串常值的結構如下所示,其中 N
是 interpolated_string_expression 中的插補數目:The format string literal is constructed as follows, where N
is the number of interpolations in the interpolated_string_expression:
- 如果 interpolated_regular_string_whole 或 interpolated_verbatim_string_whole 遵循
$
正負號,則格式字串常值就是該 token。If an interpolated_regular_string_whole or an interpolated_verbatim_string_whole follows the$
sign, then the format string literal is that token. - 否則,格式字串常值包含:Otherwise, the format string literal consists of:
- 第一個 interpolated_regular_string_start 或 interpolated_verbatim_string_startFirst the interpolated_regular_string_start or interpolated_verbatim_string_start
- 然後,針對每個數位
I
0
N-1
:Then for each numberI
from0
toN-1
:- 的十進位標記法
I
The decimal representation ofI
- 然後,如果對應的 插補 有 constant_expression,則
,
(逗點) ,後面接著 constant_expression 值的十進位標記法。Then, if the corresponding interpolation has a constant_expression, a,
(comma) followed by the decimal representation of the value of the constant_expression - 然後, interpolated_regular_string_mid、 interpolated_regular_string_end、 interpolated_verbatim_string_mid 或緊接在對應的插補之後的 interpolated_verbatim_string_end 。Then the interpolated_regular_string_mid, interpolated_regular_string_end, interpolated_verbatim_string_mid or interpolated_verbatim_string_end immediately following the corresponding interpolation.
- 的十進位標記法
後續的引數只是 插補 中的 運算式 (如有任何) 順序。The subsequent arguments are simply the expressions from the interpolations (if any), in order.
TODO:範例。TODO: examples.
簡單名稱Simple names
Simple_name 包含識別碼,並選擇性地接著類型引數清單:A simple_name consists of an identifier, optionally followed by a type argument list:
simple_name
: identifier type_argument_list?
;
Simple_name 是表單 I
或表單的格式 I<A1,...,Ak>
,其中 I
是單一識別碼,而且 <A1,...,Ak>
是選擇性的 type_argument_list。A simple_name is either of the form I
or of the form I<A1,...,Ak>
, where I
is a single identifier and <A1,...,Ak>
is an optional type_argument_list. 未指定任何 type_argument_list 時,請考慮為 K
零。When no type_argument_list is specified, consider K
to be zero. Simple_name 的評估和分類方式如下:The simple_name is evaluated and classified as follows:
如果
K
為零,且 simple_name 出現在 區塊 中,而且 區塊 的 (或封閉 區塊 的) 區域變數宣告空間 (宣告) 包含 區域變數、參數或具有名稱的常數I
,則 simple_name 會參考該區域變數、參數或常數,並分類為變數或值。IfK
is zero and the simple_name appears within a block and if the block's (or an enclosing block's) local variable declaration space (Declarations) contains a local variable, parameter or constant with nameI
, then the simple_name refers to that local variable, parameter or constant and is classified as a variable or value.如果
K
為零,且 simple_name 出現在泛型方法宣告的主體中,且該宣告包含具有名稱的類型參數I
,則 simple_name 會參考該類型參數。IfK
is zero and the simple_name appears within the body of a generic method declaration and if that declaration includes a type parameter with nameI
, then the simple_name refers to that type parameter.否則,針對每個實例類型
T
(實例類型) ,從立即封入類型宣告的實例類型開始,然後繼續執行每個封入類別或結構宣告的實例類型 (如果有任何) :Otherwise, for each instance typeT
(The instance type), starting with the instance type of the immediately enclosing type declaration and continuing with the instance type of each enclosing class or struct declaration (if any):- 如果
K
為零,且的宣告T
包含具有名稱的型別參數I
,則 simple_name 會參考該型別參數。IfK
is zero and the declaration ofT
includes a type parameter with nameI
, then the simple_name refers to that type parameter. - 否則,如果成員查閱 (成員查閱) 的
I
inT
具有類型引數,則會K
產生相符的結果:Otherwise, if a member lookup (Member lookup) ofI
inT
withK
type arguments produces a match:- 如果
T
是直接封入類別或結構類型的實例類型,而且查閱識別出一或多個方法,則結果為具有相關聯之實例運算式的方法群組this
。IfT
is the instance type of the immediately enclosing class or struct type and the lookup identifies one or more methods, the result is a method group with an associated instance expression ofthis
. 如果指定了類型引數清單,則會使用它來呼叫泛型方法, (方法調用) 。If a type argument list was specified, it is used in calling a generic method (Method invocations). - 否則,如果
T
是直接封入類別或結構類型的實例類型,如果查閱識別實例成員,且參考發生在實例函式的主體、實例方法或實例存取子內,則結果與表單的成員存取 (成員存取) 相同this.I
。Otherwise, ifT
is the instance type of the immediately enclosing class or struct type, if the lookup identifies an instance member, and if the reference occurs within the body of an instance constructor, an instance method, or an instance accessor, the result is the same as a member access (Member access) of the formthis.I
. 只有當為零時,才會發生這種情況K
。This can only happen whenK
is zero. - 否則,結果會與表單或的成員存取 (成員存取) 相同
T.I
T.I<A1,...,Ak>
。Otherwise, the result is the same as a member access (Member access) of the formT.I
orT.I<A1,...,Ak>
. 在此情況下,它是系結時期錯誤, simple_name 參考實例成員。In this case, it is a binding-time error for the simple_name to refer to an instance member.
- 如果
- 如果
否則,針對每個命名空間
N
,從 simple_name 發生所在的命名空間開始,繼續每個封入命名空間 (如果有任何) ,並以全域命名空間結束,則會評估下列步驟,直到實體找到為止:Otherwise, for each namespaceN
, starting with the namespace in which the simple_name occurs, continuing with each enclosing namespace (if any), and ending with the global namespace, the following steps are evaluated until an entity is located:- 如果
K
是零,且I
是命名空間的名稱N
,則:IfK
is zero andI
is the name of a namespace inN
, then:- 如果發生 simple_name 的位置是由命名空間宣告所括住,
N
且命名空間宣告包含 extern_alias_directive 或 using_alias_directive ,將名稱I
與命名空間或類型產生關聯,則 simple_name 不明確,而且會發生編譯時期錯誤。If the location where the simple_name occurs is enclosed by a namespace declaration forN
and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the nameI
with a namespace or type, then the simple_name is ambiguous and a compile-time error occurs. - 否則, simple_name 會參考中的命名空間
I
N
。Otherwise, the simple_name refers to the namespace namedI
inN
.
- 如果發生 simple_name 的位置是由命名空間宣告所括住,
- 否則,如果
N
包含具有 name 和 type 參數的可存取型別I
K
,則:Otherwise, ifN
contains an accessible type having nameI
andK
type parameters, then:- 如果
K
是零,且 simple_name 發生的位置是以命名空間宣告括住,N
且命名空間宣告包含 extern_alias_directive 或 using_alias_directive ,將名稱I
與命名空間或類型產生關聯,則 simple_name 不明確,而且會發生編譯時期錯誤。IfK
is zero and the location where the simple_name occurs is enclosed by a namespace declaration forN
and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the nameI
with a namespace or type, then the simple_name is ambiguous and a compile-time error occurs. - 否則, namespace_or_type_name 會參考以指定的型別引數所構成的型別。Otherwise, the namespace_or_type_name refers to the type constructed with the given type arguments.
- 如果
- 否則,如果 simple_name 發生的位置是以的命名空間宣告括住
N
:Otherwise, if the location where the simple_name occurs is enclosed by a namespace declaration forN
:- 如果
K
為零,且命名空間宣告包含 extern_alias_directive 或 using_alias_directive ,將名稱I
與匯入的命名空間或類型產生關聯,則 simple_name 會參考該命名空間或類型。IfK
is zero and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the nameI
with an imported namespace or type, then the simple_name refers to that namespace or type. - 否則,如果由命名空間宣告的 using_namespace_directive s 和 using_static_directive s 所匯入的命名空間和類型宣告,只包含一個可存取的類型或具有名稱和類型參數的非延伸靜態成員
I
,則K
simple_name 會參考以指定類型引數所建立的該類型或成員。Otherwise, if the namespaces and type declarations imported by the using_namespace_directive s and using_static_directive s of the namespace declaration contain exactly one accessible type or non-extension static member having nameI
andK
type parameters, then the simple_name refers to that type or member constructed with the given type arguments. - 否則,如果命名空間宣告的 using_namespace_directive s 所匯入的命名空間和型別包含一個以上的可存取型別或非延伸方法靜態成員具有 name
I
和K
type 參數,則 simple_name 會不明確,而且會發生錯誤。Otherwise, if the namespaces and types imported by the using_namespace_directive s of the namespace declaration contain more than one accessible type or non-extension-method static member having nameI
andK
type parameters, then the simple_name is ambiguous and an error occurs.
- 如果
請注意,這整個步驟與處理 namespace_or_type_name (命名空間和類型名稱) 的對應步驟完全相同。Note that this entire step is exactly parallel to the corresponding step in the processing of a namespace_or_type_name (Namespace and type names).
- 如果
否則, simple_name 是未定義的,而且會發生編譯時期錯誤。Otherwise, the simple_name is undefined and a compile-time error occurs.
括號運算式Parenthesized expressions
Parenthesized_expression 是由以括弧括住的 運算式 所組成。A parenthesized_expression consists of an expression enclosed in parentheses.
parenthesized_expression
: '(' expression ')'
;
Parenthesized_expression 是藉由評估括弧內的 運算式 來評估。A parenthesized_expression is evaluated by evaluating the expression within the parentheses. 如果括弧內的 運算式 表示命名空間或類型,就會發生編譯階段錯誤。If the expression within the parentheses denotes a namespace or type, a compile-time error occurs. 否則, parenthesized_expression 的結果會是所含 運算式 的評估結果。Otherwise, the result of the parenthesized_expression is the result of the evaluation of the contained expression.
成員存取Member access
Member_access 由 primary_expression、 predefined_type 或 qualified_alias_member 所組成,後面接著 " .
" token,後面接著一個 識別碼,可選擇性地接著 type_argument_list。A member_access consists of a primary_expression, a predefined_type, or a qualified_alias_member, followed by a ".
" token, followed by an identifier, optionally followed by a type_argument_list.
member_access
: primary_expression '.' identifier type_argument_list?
| predefined_type '.' identifier type_argument_list?
| qualified_alias_member '.' identifier
;
predefined_type
: 'bool' | 'byte' | 'char' | 'decimal' | 'double' | 'float' | 'int' | 'long'
| 'object' | 'sbyte' | 'short' | 'string' | 'uint' | 'ulong' | 'ushort'
;
Qualified_alias_member 生產環境是在 命名空間別名限定詞中定義。The qualified_alias_member production is defined in Namespace alias qualifiers.
Member_access 的格式為表單 E.I
或形式 E.I<A1, ..., Ak>
,其中 E
是主要運算式、是 I
單一識別碼,而且 <A1, ..., Ak>
是選擇性的 type_argument_list。A member_access is either of the form E.I
or of the form E.I<A1, ..., Ak>
, where E
is a primary-expression, I
is a single identifier and <A1, ..., Ak>
is an optional type_argument_list. 未指定任何 type_argument_list 時,請考慮為 K
零。When no type_argument_list is specified, consider K
to be zero.
具有類型之 primary_expression 的 member_access 會動態系結 dynamic
(動態繫結) 。A member_access with a primary_expression of type dynamic
is dynamically bound (Dynamic binding). 在此情況下,編譯器會將成員存取分類為型別的屬性存取 dynamic
。In this case the compiler classifies the member access as a property access of type dynamic
. 以下規則會在執行時間使用執行時間類型,而不是 primary_expression 的編譯時間類型,以判斷 member_access 的意義。The rules below to determine the meaning of the member_access are then applied at run-time, using the run-time type instead of the compile-time type of the primary_expression. 如果這個執行時間分類會導致方法群組,則成員存取必須是 invocation_expression 的 primary_expression 。If this run-time classification leads to a method group, then the member access must be the primary_expression of an invocation_expression.
Member_access 的評估和分類方式如下:The member_access is evaluated and classified as follows:
- 如果
K
是零,而且E
是命名空間且E
包含具有名稱的嵌套命名空間I
,則結果為該命名空間。IfK
is zero andE
is a namespace andE
contains a nested namespace with nameI
, then the result is that namespace. - 否則,如果
E
是命名空間,而且E
包含具有名稱和類型參數的可存取型別I
,則K
結果會是以指定的型別引數所構成的型別。Otherwise, ifE
is a namespace andE
contains an accessible type having nameI
andK
type parameters, then the result is that type constructed with the given type arguments. - 如果
E
是 predefined_type 或分類為類型的 primary_expression ,如果不是E
型別參數,而且如果成員查閱 (的成員查閱) 中的I
型別E
K
參數產生相符的,則E.I
會進行評估並分類如下:IfE
is a predefined_type or a primary_expression classified as a type, ifE
is not a type parameter, and if a member lookup (Member lookup) ofI
inE
withK
type parameters produces a match, thenE.I
is evaluated and classified as follows:- 如果
I
識別型別,則結果是以指定的型別引數所構成的型別。IfI
identifies a type, then the result is that type constructed with the given type arguments. - 如果
I
識別一或多個方法,則結果為沒有相關聯實例運算式的方法群組。IfI
identifies one or more methods, then the result is a method group with no associated instance expression. 如果指定了類型引數清單,則會使用它來呼叫泛型方法, (方法調用) 。If a type argument list was specified, it is used in calling a generic method (Method invocations). - 如果
I
識別static
屬性,則結果會是沒有相關聯的實例運算式的屬性存取。IfI
identifies astatic
property, then the result is a property access with no associated instance expression. - 如果
I
識別static
欄位:IfI
identifies astatic
field:- 如果欄位是
readonly
,而參考出現在宣告欄位之類別或結構的靜態函式之外,則結果為值,亦即中靜態欄位的值I
E
。If the field isreadonly
and the reference occurs outside the static constructor of the class or struct in which the field is declared, then the result is a value, namely the value of the static fieldI
inE
. - 否則,結果會是變數,也就是中的靜態欄位
I
E
。Otherwise, the result is a variable, namely the static fieldI
inE
.
- 如果欄位是
- 如果
I
識別static
事件:IfI
identifies astatic
event:- 如果參考出現在宣告事件的類別或結構中,且事件已在沒有 event_accessor_declarations (事件) 的情況下宣告,則
E.I
會完全如同I
靜態欄位一樣處理。If the reference occurs within the class or struct in which the event is declared, and the event was declared without event_accessor_declarations (Events), thenE.I
is processed exactly as ifI
were a static field. - 否則,結果會是沒有相關聯的實例運算式的事件存取。Otherwise, the result is an event access with no associated instance expression.
- 如果參考出現在宣告事件的類別或結構中,且事件已在沒有 event_accessor_declarations (事件) 的情況下宣告,則
- 如果
I
識別常數,則結果為值,亦即該常數的值。IfI
identifies a constant, then the result is a value, namely the value of that constant. - 如果
I
識別列舉成員,則結果為值,亦即該列舉成員的值。IfI
identifies an enumeration member, then the result is a value, namely the value of that enumeration member. - 否則,
E.I
就是不正確成員參考,而且會發生編譯時期錯誤。Otherwise,E.I
is an invalid member reference, and a compile-time error occurs.
- 如果
- 如果
E
是屬性存取、索引子存取、變數或值、的型別為的型別,T
而 with 型別引數的成員查閱 (成員查閱) 會I
T
K
產生相符的E.I
結果,則會進行評估並分類如下:IfE
is a property access, indexer access, variable, or value, the type of which isT
, and a member lookup (Member lookup) ofI
inT
withK
type arguments produces a match, thenE.I
is evaluated and classified as follows:- 首先,如果
E
是屬性或索引子存取,則會取得 (運算式值) 的屬性或索引子存取值,並將其重新分類E
為值。First, ifE
is a property or indexer access, then the value of the property or indexer access is obtained (Values of expressions) andE
is reclassified as a value. - 如果
I
識別一或多個方法,則結果為具有相關聯之實例運算式的方法群組E
。IfI
identifies one or more methods, then the result is a method group with an associated instance expression ofE
. 如果指定了類型引數清單,則會使用它來呼叫泛型方法, (方法調用) 。If a type argument list was specified, it is used in calling a generic method (Method invocations). - 如果
I
識別實例屬性,IfI
identifies an instance property,- 如果
E
為this
,則會I
識別自動執行的屬性 (自動 實) 沒有 setter 的屬性,而且在類別或結構類型的實例的函式中發生參考,T
則結果為變數,也就是由I
指定之實例中所指定之 auto 屬性的隱藏支援欄位T
this
。IfE
isthis
,I
identifies an automatically implemented property (Automatically implemented properties) without a setter, and the reference occurs within an instance constructor for a class or struct typeT
, then the result is a variable, namely the hidden backing field for the auto-property given byI
in the instance ofT
given bythis
. - 否則,結果會是具有相關聯的實例運算式的屬性存取
E
。Otherwise, the result is a property access with an associated instance expression ofE
.
- 如果
- 如果
T
是 class_type ,並I
識別該 class_type 的實例欄位:IfT
is a class_type andI
identifies an instance field of that class_type:- 如果的值
E
為,則會擲回null
System.NullReferenceException
。If the value ofE
isnull
, then aSystem.NullReferenceException
is thrown. - 否則,如果欄位是
readonly
,而參考出現在宣告欄位之類別的實例函式之外,則結果為值,也就是所參考之物件中的域值I
E
。Otherwise, if the field isreadonly
and the reference occurs outside an instance constructor of the class in which the field is declared, then the result is a value, namely the value of the fieldI
in the object referenced byE
. - 否則,結果會是變數,也就是所
I
參考之物件中的欄位E
。Otherwise, the result is a variable, namely the fieldI
in the object referenced byE
.
- 如果的值
- 如果
T
是 struct_type ,並I
識別該 struct_type 的實例欄位:IfT
is a struct_type andI
identifies an instance field of that struct_type:- 如果
E
是值,或如果欄位是,readonly
而參考出現在宣告欄位之結構的實例函式之外,則結果為值,也就是I
指定之結構實例中的欄位值E
。IfE
is a value, or if the field isreadonly
and the reference occurs outside an instance constructor of the struct in which the field is declared, then the result is a value, namely the value of the fieldI
in the struct instance given byE
. - 否則,結果會是變數,也就是
I
指定之結構實例中的欄位E
。Otherwise, the result is a variable, namely the fieldI
in the struct instance given byE
.
- 如果
- 如果
I
識別實例事件:IfI
identifies an instance event:- 如果參考出現在宣告事件的類別或結構中,且事件未 event_accessor_declarations (事件) 的情況下宣告,而且參考不會在或運算子的左邊進行
+=
,則-=
E.I
會如同I
實例欄位一樣處理該參考。If the reference occurs within the class or struct in which the event is declared, and the event was declared without event_accessor_declarations (Events), and the reference does not occur as the left-hand side of a+=
or-=
operator, thenE.I
is processed exactly as ifI
was an instance field. - 否則,結果會是具有相關聯之實例運算式的事件存取
E
。Otherwise, the result is an event access with an associated instance expression ofE
.
- 如果參考出現在宣告事件的類別或結構中,且事件未 event_accessor_declarations (事件) 的情況下宣告,而且參考不會在或運算子的左邊進行
- 首先,如果
- 否則,系統會嘗試將
E.I
(擴充方法 調用) 的擴充方法調用進行處理。Otherwise, an attempt is made to processE.I
as an extension method invocation (Extension method invocations). 如果失敗,E.I
是不正確成員參考,且發生系結階段錯誤。If this fails,E.I
is an invalid member reference, and a binding-time error occurs.
相同的簡單名稱和類型名稱Identical simple names and type names
在表單的成員存取中 E.I
,如果 E
是單一識別碼,而且如果 E
Simple_name 的意義 (簡單名稱) 是常數、欄位、屬性、區域變數或參數,其類型與 E
type_name (命名空間和類型名稱 的意義相同,則允許這兩種可能的含意 E
。In a member access of the form E.I
, if E
is a single identifier, and if the meaning of E
as a simple_name (Simple names) is a constant, field, property, local variable, or parameter with the same type as the meaning of E
as a type_name (Namespace and type names), then both possible meanings of E
are permitted. 這兩種可能的含意 E.I
永遠不可混淆,因為 I
E
在這兩種情況下都必須是類型的成員。The two possible meanings of E.I
are never ambiguous, since I
must necessarily be a member of the type E
in both cases. 換句話說,此規則只會允許存取靜態成員,以及可能 E
發生編譯時期錯誤的巢狀型別。In other words, the rule simply permits access to the static members and nested types of E
where a compile-time error would otherwise have occurred. 例如:For example:
struct Color
{
public static readonly Color White = new Color(...);
public static readonly Color Black = new Color(...);
public Color Complement() {...}
}
class A
{
public Color Color; // Field Color of type Color
void F() {
Color = Color.Black; // References Color.Black static member
Color = Color.Complement(); // Invokes Complement() on Color field
}
static void G() {
Color c = Color.White; // References Color.White static member
}
}
文法多義性Grammar ambiguities
Simple_name (簡單名稱的生產) 和 Member_access (成員存取) 可能會在運算式的文法中提供明顯的多義性。The productions for simple_name (Simple names) and member_access (Member access) can give rise to ambiguities in the grammar for expressions. 例如,語句:For example, the statement:
F(G<A,B>(7));
可以 F
用兩個引數(和)的呼叫來解讀 G < A
B > (7)
。could be interpreted as a call to F
with two arguments, G < A
and B > (7)
. 或者,您也可以使用一個引數來將它解釋為呼叫 F
,此引數是 G
使用兩個型別引數和一個一般引數呼叫泛型方法。Alternatively, it could be interpreted as a call to F
with one argument, which is a call to a generic method G
with two type arguments and one regular argument.
如果可以將內容) 中的 token 序列 (為 simple_name (簡單名稱) 、 member_access (成員存取) ,或 Pointer_member_access (指標成員存取) 以 type_argument_list ( 類型引數) 結尾,則會檢查緊接在結尾 token 之後的權杖 >
。If a sequence of tokens can be parsed (in context) as a simple_name (Simple names), member_access (Member access), or pointer_member_access (Pointer member access) ending with a type_argument_list (Type arguments), the token immediately following the closing >
token is examined. 如果是下列其中一項If it is one of
( ) ] } : ; , . ? == != | ^
然後, type_argument_list 會保留為 simple_name、 member_access 或 pointer_member_access 的一部分,而且會捨棄權杖序列順序的任何其他可能剖析。then the type_argument_list is retained as part of the simple_name, member_access or pointer_member_access and any other possible parse of the sequence of tokens is discarded. 否則,即使沒有其他可能的權杖順序剖析, type_argument_list 也不會被視為 simple_name、 member_access 或 pointer_member_access 的一部分。Otherwise, the type_argument_list is not considered to be part of the simple_name, member_access or pointer_member_access, even if there is no other possible parse of the sequence of tokens. 請注意,在 namespace_or_type_name (命名空間和類型名稱) 中剖析 type_argument_list 時,不會套用這些規則。Note that these rules are not applied when parsing a type_argument_list in a namespace_or_type_name (Namespace and type names). 陳述式The statement
F(G<A,B>(7));
根據此規則,將會以一個引數的呼叫來解讀,此 F
引數是 G
使用兩個型別引數和一個一般引數呼叫泛型方法。will, according to this rule, be interpreted as a call to F
with one argument, which is a call to a generic method G
with two type arguments and one regular argument. 語句The statements
F(G < A, B > 7);
F(G < A, B >> 7);
每個都會以兩個引數的呼叫來解讀 F
。will each be interpreted as a call to F
with two arguments. 陳述式The statement
x = F < A > +y;
會以小於運算子、大於運算子和一元加號運算子的形式來解讀,如同已寫入語句 x = (F < A) > (+y)
,而不是 type_argument_list 後面接著二元加號運算子的 simple_name 。will be interpreted as a less than operator, greater than operator, and unary plus operator, as if the statement had been written x = (F < A) > (+y)
, instead of as a simple_name with a type_argument_list followed by a binary plus operator. 在語句中In the statement
x = y is C<T> + z;
標記 C<T>
會以 type_argument_list 的 namespace_or_type_name 來解讀。the tokens C<T>
are interpreted as a namespace_or_type_name with a type_argument_list.
叫用運算式Invocation expressions
用來叫用方法的 invocation_expression 。An invocation_expression is used to invoke a method.
invocation_expression
: primary_expression '(' argument_list? ')'
;
如果至少有下列其中一個保存, invocation_expression 會動態系結 (動態繫結) :An invocation_expression is dynamically bound (Dynamic binding) if at least one of the following holds:
- Primary_expression 具有編譯時間類型
dynamic
。The primary_expression has compile-time typedynamic
. - 選擇性 argument_list 至少有一個引數具有編譯時間類型
dynamic
,而且 primary_expression 沒有委派類型。At least one argument of the optional argument_list has compile-time typedynamic
and the primary_expression does not have a delegate type.
在此情況下,編譯器會將 invocation_expression 分類為類型的值 dynamic
。In this case the compiler classifies the invocation_expression as a value of type dynamic
. 以下規則會在執行時間使用執行時間類型,而不是具有編譯時間類型之 primary_expression 和引數的編譯時間類型,以判斷 invocation_expression 的意義 dynamic
。The rules below to determine the meaning of the invocation_expression are then applied at run-time, using the run-time type instead of the compile-time type of those of the primary_expression and arguments which have the compile-time type dynamic
. 如果 primary_expression 沒有編譯時間型別 dynamic
,則方法調用會進行有限的編譯時間檢查,如動態多載 解析的編譯時間檢查中所述。If the primary_expression does not have compile-time type dynamic
, then the method invocation undergoes a limited compile time check as described in Compile-time checking of dynamic overload resolution.
Invocation_expression 的 primary_expression 必須是方法群組或 delegate_type 的值。The primary_expression of an invocation_expression must be a method group or a value of a delegate_type. 如果 primary_expression 是方法群組,則 invocation_expression 是方法調用, (方法 調用) 。If the primary_expression is a method group, the invocation_expression is a method invocation (Method invocations). 如果 primary_expression 是 delegate_type 的值,則 invocation_expression 為委派調用, (委派調用) 。If the primary_expression is a value of a delegate_type, the invocation_expression is a delegate invocation (Delegate invocations). 如果 primary_expression 不是方法群組,也不是 delegate_type 的值,則會發生系結階段錯誤。If the primary_expression is neither a method group nor a value of a delegate_type, a binding-time error occurs.
選擇性的 argument_list (引數清單) 提供方法參數的值或變數參考。The optional argument_list (Argument lists) provides values or variable references for the parameters of the method.
評估 invocation_expression 的結果分類如下:The result of evaluating an invocation_expression is classified as follows:
- 如果 invocation_expression 叫用傳回的方法或委派
void
,則結果為 nothing。If the invocation_expression invokes a method or delegate that returnsvoid
, the result is nothing. 分類為 nothing 的運算式只允許在 statement_expression (運算式語句 的內容中) 或作為 lambda_expression (匿名函式 運算式 的主體) 。An expression that is classified as nothing is permitted only in the context of a statement_expression (Expression statements) or as the body of a lambda_expression (Anonymous function expressions). 否則,就會發生系結階段錯誤。Otherwise a binding-time error occurs. - 否則,結果會是方法或委派所傳回之類型的值。Otherwise, the result is a value of the type returned by the method or delegate.
方法調用Method invocations
若為方法調用, invocation_expression 的 primary_expression 必須是方法群組。For a method invocation, the primary_expression of the invocation_expression must be a method group. 方法群組會識別要叫用的一個方法或一組多載的方法,以從中選擇要叫用的特定方法。The method group identifies the one method to invoke or the set of overloaded methods from which to choose a specific method to invoke. 在後者的情況下,判斷要叫用的特定方法是根據 argument_list 中的引數類型所提供的內容。In the latter case, determination of the specific method to invoke is based on the context provided by the types of the arguments in the argument_list.
表單方法調用的系結時間處理 M(A)
(其中 M
是方法群組 (可能包含 type_argument_list) ,而 A
是選擇性的 argument_list,包含下列步驟:The binding-time processing of a method invocation of the form M(A)
, where M
is a method group (possibly including a type_argument_list), and A
is an optional argument_list, consists of the following steps:
- 會建立方法調用的候選方法集合。The set of candidate methods for the method invocation is constructed. 針對
F
與方法群組相關聯的每個方法M
:For each methodF
associated with the method groupM
:- 如果
F
是非泛型,則在下列情況下F
為候選:IfF
is non-generic,F
is a candidate when:M
沒有類型引數清單,且為M
has no type argument list, andF
適用于A
(適用的函數成員) 。F
is applicable with respect toA
(Applicable function member).
- 如果
F
是泛型且沒有M
類型引數清單,F
則在下列情況下是候選項:IfF
is generic andM
has no type argument list,F
is a candidate when:- 型別推斷 (類型推斷) 成功、推斷呼叫類型引數的清單,以及Type inference (Type inference) succeeds, inferring a list of type arguments for the call, and
- 當推斷的型別引數取代為對應的方法型別參數時,F 的參數清單中的所有結構化型別都會滿足其條件約束, (符合) 的 條件約束 ,而的參數清單
F
適用于A
(適用的函數成員) 。Once the inferred type arguments are substituted for the corresponding method type parameters, all constructed types in the parameter list of F satisfy their constraints (Satisfying constraints), and the parameter list ofF
is applicable with respect toA
(Applicable function member).
- 如果
F
是泛型且M
包含型別引數清單,則在下列情況下F
是候選項:IfF
is generic andM
includes a type argument list,F
is a candidate when:F
具有與類型引數清單中所提供之相同的方法類型參數數目,以及F
has the same number of method type parameters as were supplied in the type argument list, and- 一旦將型別引數替換為對應的方法型別參數,F 的參數清單中的所有結構化型別就會滿足其條件約束, (符合) 的 條件約束 ,而的參數清單
F
適用于A
(適用的函數成員) 。Once the type arguments are substituted for the corresponding method type parameters, all constructed types in the parameter list of F satisfy their constraints (Satisfying constraints), and the parameter list ofF
is applicable with respect toA
(Applicable function member).
- 如果
- 這組候選方法會縮減成隻包含來自最多衍生類型的方法:針對集合中的每個方法
C.F
,其中C
是宣告方法的類型,F
在基底類型中宣告的所有方法C
都會從集合中移除。The set of candidate methods is reduced to contain only methods from the most derived types: For each methodC.F
in the set, whereC
is the type in which the methodF
is declared, all methods declared in a base type ofC
are removed from the set. 此外,如果C
是以外的類別型別object
,則會從集合中移除在介面型別中宣告的所有方法。Furthermore, ifC
is a class type other thanobject
, all methods declared in an interface type are removed from the set. (這個第二個規則只有當方法群組是成員查閱的結果,而該型別參數具有物件以外的有效基類和非空白的有效介面集時,才會有影響。 ) (This latter rule only has affect when the method group was the result of a member lookup on a type parameter having an effective base class other than object and a non-empty effective interface set.) - 如果產生的候選方法集合是空的,則會放棄下列步驟的進一步處理,而改為嘗試將叫用視為擴充方法調用, (擴充方法 調用) 。If the resulting set of candidate methods is empty, then further processing along the following steps are abandoned, and instead an attempt is made to process the invocation as an extension method invocation (Extension method invocations). 如果失敗,就不會有任何適用的方法存在,而且會發生系結階段錯誤。If this fails, then no applicable methods exist, and a binding-time error occurs.
- 您可以使用多載解析規則的多 載解析規則來識別候選方法集合的最佳方法。The best method of the set of candidate methods is identified using the overload resolution rules of Overload resolution. 如果無法識別單一最佳方法,則方法調用會不明確,而且會發生系結階段錯誤。If a single best method cannot be identified, the method invocation is ambiguous, and a binding-time error occurs. 執行多載解析時,會在將類型引數替換為對應方法類型參數的 (提供或推斷) 之後,考慮泛型方法的參數。When performing overload resolution, the parameters of a generic method are considered after substituting the type arguments (supplied or inferred) for the corresponding method type parameters.
- 執行所選最佳方法的最終驗證:Final validation of the chosen best method is performed:
- 方法會在方法群組的內容中進行驗證:如果最理想的方法是靜態方法,則方法群組必須由 simple_name 或 member_access 透過型別產生。The method is validated in the context of the method group: If the best method is a static method, the method group must have resulted from a simple_name or a member_access through a type. 如果最佳方法是實例方法,則方法群組必須由 simple_name、透過變數或值 member_access ,或 base_access 所產生。If the best method is an instance method, the method group must have resulted from a simple_name, a member_access through a variable or value, or a base_access. 如果上述兩項需求都不成立,就會發生系結階段錯誤。If neither of these requirements is true, a binding-time error occurs.
- 如果最理想的方法是泛型方法, (提供或) 推斷的型別引數會根據條件約束進行檢查, (滿足泛型方法) 所宣告的 條件約束 。If the best method is a generic method, the type arguments (supplied or inferred) are checked against the constraints (Satisfying constraints) declared on the generic method. 如果任何類型引數無法滿足類型參數上 (s) 的對應條件約束,就會發生系結階段錯誤。If any type argument does not satisfy the corresponding constraint(s) on the type parameter, a binding-time error occurs.
在上述步驟的系結時間選取並驗證方法之後,就會根據動態多載 解析的編譯時間檢查中所述的函數成員調用規則,來處理實際的執行時間調用。Once a method has been selected and validated at binding-time by the above steps, the actual run-time invocation is processed according to the rules of function member invocation described in Compile-time checking of dynamic overload resolution.
上述解析規則的直覺效果如下所示:若要找出方法調用所叫用的特定方法,請從方法調用所指示的型別開始,然後繼續繼承鏈,直到找到至少一個適用、可存取的非覆寫方法宣告為止。The intuitive effect of the resolution rules described above is as follows: To locate the particular method invoked by a method invocation, start with the type indicated by the method invocation and proceed up the inheritance chain until at least one applicable, accessible, non-override method declaration is found. 然後,在該型別中宣告的適用、可存取、非覆寫方法集合上執行型別推斷和多載解析,然後再叫用選取的方法。Then perform type inference and overload resolution on the set of applicable, accessible, non-override methods declared in that type and invoke the method thus selected. 如果找不到方法,請改為將叫用視為擴充方法叫用來處理。If no method was found, try instead to process the invocation as an extension method invocation.
擴充方法調用Extension method invocations
在方法調用中 (在其中一個表單) 的已封裝實例上調用In a method invocation (Invocations on boxed instances) of one of the forms
expr . identifier ( )
expr . identifier ( args )
expr . identifier < typeargs > ( )
expr . identifier < typeargs > ( args )
如果調用的正常處理找不到任何適用的方法,則會嘗試將結構視為擴充方法調用來處理。if the normal processing of the invocation finds no applicable methods, an attempt is made to process the construct as an extension method invocation. 如果 expr 或任何引數 都有編譯 時間類型 dynamic
,將不會套用擴充方法。If expr or any of the args has compile-time type dynamic
, extension methods will not apply.
目標是要尋找最佳的 type_name C
,以便進行對應的靜態方法調用:The objective is to find the best type_name C
, so that the corresponding static method invocation can take place:
C . identifier ( expr )
C . identifier ( expr , args )
C . identifier < typeargs > ( expr )
C . identifier < typeargs > ( expr , args )
擴充方法 Ci.Mj
符合下列 條件 :An extension method Ci.Mj
is eligible if:
Ci
是非泛型、非嵌套類別Ci
is a non-generic, non-nested class- 的名稱
Mj
是 識別碼The name ofMj
is identifier Mj
適用于將引數套用至引數作為靜態方法時,如上所示Mj
is accessible and applicable when applied to the arguments as a static method as shown above- 從 expr 到的第一個參數型別,都有隱含的識別、參考或裝箱轉換
Mj
。An implicit identity, reference or boxing conversion exists from expr to the type of the first parameter ofMj
.
搜尋會繼續進行,如下所示 C
:The search for C
proceeds as follows:
- 從最接近的封入命名空間宣告開始,繼續每個封入命名空間宣告,並以包含的編譯單位結束,就會進行後續的嘗試,以找出一組候選的擴充方法:Starting with the closest enclosing namespace declaration, continuing with each enclosing namespace declaration, and ending with the containing compilation unit, successive attempts are made to find a candidate set of extension methods:
- 如果指定的命名空間或編譯單位直接包含具有合格延伸方法的非泛型型別宣告
Ci
Mj
,則這些擴充方法的集合就是候選集合。If the given namespace or compilation unit directly contains non-generic type declarationsCi
with eligible extension methodsMj
, then the set of those extension methods is the candidate set. - 如果 using_static_declarations 匯入的型別
Ci
,以及在指定的命名空間或編譯單位中 using_namespace_directive s 匯入之命名空間中直接宣告的型別包含合格的擴充方法Mj
,則這些擴充方法的集合就是候選集合。If typesCi
imported by using_static_declarations and directly declared in namespaces imported by using_namespace_directive s in the given namespace or compilation unit directly contain eligible extension methodsMj
, then the set of those extension methods is the candidate set.
- 如果指定的命名空間或編譯單位直接包含具有合格延伸方法的非泛型型別宣告
- 如果在任何封入命名空間宣告或編譯單位中都找不到候選集合,則會發生編譯時期錯誤。If no candidate set is found in any enclosing namespace declaration or compilation unit, a compile-time error occurs.
- 否則,多載解析會套用至候選集合,如 (多載 解析) 中所述。Otherwise, overload resolution is applied to the candidate set as described in (Overload resolution). 如果找不到單一最佳方法,就會發生編譯時期錯誤。If no single best method is found, a compile-time error occurs.
C
這是在其中將最佳方法宣告為擴充方法的型別。C
is the type within which the best method is declared as an extension method.
使用 C
做為目標時,方法呼叫接著會處理為靜態方法調用, (動態多載解析) 的編譯時期檢查 。Using C
as a target, the method call is then processed as a static method invocation (Compile-time checking of dynamic overload resolution).
上述規則表示實例方法優先于擴充方法,內部命名空間宣告中提供的擴充方法優先于外部命名空間宣告中可用的擴充方法,而且直接在命名空間中宣告的擴充方法,優先于使用命名空間指示詞彙入至該相同命名空間的擴充方法。The preceding rules mean that instance methods take precedence over extension methods, that extension methods available in inner namespace declarations take precedence over extension methods available in outer namespace declarations, and that extension methods declared directly in a namespace take precedence over extension methods imported into that same namespace with a using namespace directive. 例如:For example:
public static class E
{
public static void F(this object obj, int i) { }
public static void F(this object obj, string s) { }
}
class A { }
class B
{
public void F(int i) { }
}
class C
{
public void F(object obj) { }
}
class X
{
static void Test(A a, B b, C c) {
a.F(1); // E.F(object, int)
a.F("hello"); // E.F(object, string)
b.F(1); // B.F(int)
b.F("hello"); // E.F(object, string)
c.F(1); // C.F(object)
c.F("hello"); // C.F(object)
}
}
在此範例中, B
的方法優先于第一個擴充方法,而 C
的方法優先于這兩種擴充方法。In the example, B
's method takes precedence over the first extension method, and C
's method takes precedence over both extension methods.
public static class C
{
public static void F(this int i) { Console.WriteLine("C.F({0})", i); }
public static void G(this int i) { Console.WriteLine("C.G({0})", i); }
public static void H(this int i) { Console.WriteLine("C.H({0})", i); }
}
namespace N1
{
public static class D
{
public static void F(this int i) { Console.WriteLine("D.F({0})", i); }
public static void G(this int i) { Console.WriteLine("D.G({0})", i); }
}
}
namespace N2
{
using N1;
public static class E
{
public static void F(this int i) { Console.WriteLine("E.F({0})", i); }
}
class Test
{
static void Main(string[] args)
{
1.F();
2.G();
3.H();
}
}
}
此範例的輸出為:The output of this example is:
E.F(1)
D.G(2)
C.H(3)
D.G
優先于 C.G
,且優先 E.F
于 D.F
和 C.F
。D.G
takes precedence over C.G
, and E.F
takes precedence over both D.F
and C.F
.
委派調用Delegate invocations
若為委派調用, invocation_expression 的 primary_expression 必須是 delegate_type 的值。For a delegate invocation, the primary_expression of the invocation_expression must be a value of a delegate_type. 此外,考慮 delegate_type 是與 delegate_type 具有相同參數清單的函式成員, delegate_type 必須 (適用 于) argument_list 的相關函式 成員 invocation_expression。Furthermore, considering the delegate_type to be a function member with the same parameter list as the delegate_type, the delegate_type must be applicable (Applicable function member) with respect to the argument_list of the invocation_expression.
表單的委派調用執行時間處理 D(A)
,其中 D
是 delegate_type 的 primary_expression ,而 A
是選擇性的 argument_list,其中包含下列步驟:The run-time processing of a delegate invocation of the form D(A)
, where D
is a primary_expression of a delegate_type and A
is an optional argument_list, consists of the following steps:
D
會進行評估。D
is evaluated. 如果此評估造成例外狀況,則不會執行任何進一步的步驟。If this evaluation causes an exception, no further steps are executed.- 的值
D
會被檢查為有效。The value ofD
is checked to be valid. 如果的值D
為null
,則會擲回,System.NullReferenceException
且不會執行任何進一步的步驟。If the value ofD
isnull
, aSystem.NullReferenceException
is thrown and no further steps are executed. - 否則,
D
就是委派實例的參考。Otherwise,D
is a reference to a delegate instance. 函數成員調用 (動態多載解析的編譯時間檢查) 是在委派的調用清單中的每個可呼叫實體上執行。Function member invocations (Compile-time checking of dynamic overload resolution) are performed on each of the callable entities in the invocation list of the delegate. 針對由實例和實例方法所組成的可呼叫實體,調用的實例是包含在可呼叫實體中的實例。For callable entities consisting of an instance and instance method, the instance for the invocation is the instance contained in the callable entity.
項目存取Element access
Element_access 由 primary_no_array_creation_expression 所組成,後面接著 " [
" token,後面接著 argument_list,後面接著 " ]
" token。An element_access consists of a primary_no_array_creation_expression, followed by a "[
" token, followed by an argument_list, followed by a "]
" token. Argument_list 是由一或多個 引數(以逗號分隔)所組成。The argument_list consists of one or more argument s, separated by commas.
element_access
: primary_no_array_creation_expression '[' expression_list ']'
;
Element_access 的 argument_list 不能包含 ref
或 out
引數。The argument_list of an element_access is not allowed to contain ref
or out
arguments.
如果至少有下列其中一個保存, element_access 會動態系結 (動態繫結) :An element_access is dynamically bound (Dynamic binding) if at least one of the following holds:
- Primary_no_array_creation_expression 具有編譯時間類型
dynamic
。The primary_no_array_creation_expression has compile-time typedynamic
. - Argument_list 至少有一個運算式具有編譯時間類型
dynamic
,而且 primary_no_array_creation_expression 沒有陣列類型。At least one expression of the argument_list has compile-time typedynamic
and the primary_no_array_creation_expression does not have an array type.
在此情況下,編譯器會將 element_access 分類為類型的值 dynamic
。In this case the compiler classifies the element_access as a value of type dynamic
. 下列規則可判斷 element_access 的意義,接著會在執行時間套用執行時間類型,而不是 primary_no_array_creation_expression 的編譯時間類型,以及具有編譯時間類型之 argument_list 運算式的編譯時間類型 dynamic
。The rules below to determine the meaning of the element_access are then applied at run-time, using the run-time type instead of the compile-time type of those of the primary_no_array_creation_expression and argument_list expressions which have the compile-time type dynamic
. 如果 primary_no_array_creation_expression 沒有編譯時間類型,則專案存取權會依照動態多載 dynamic
解析的編譯時間檢查所述,進行有限的編譯時間檢查。If the primary_no_array_creation_expression does not have compile-time type dynamic
, then the element access undergoes a limited compile time check as described in Compile-time checking of dynamic overload resolution.
如果 element_access 的 primary_no_array_creation_expression 是 array_type 的值,則 element_access 是陣列存取 (陣列存取) 。If the primary_no_array_creation_expression of an element_access is a value of an array_type, the element_access is an array access (Array access). 否則, primary_no_array_creation_expression 必須是具有一或多個索引子成員之類別、結構或介面類別型的變數或值,在此情況下, element_access 是索引子存取 (索引子存取) 。Otherwise, the primary_no_array_creation_expression must be a variable or value of a class, struct, or interface type that has one or more indexer members, in which case the element_access is an indexer access (Indexer access).
陣列存取Array access
針對陣列存取, element_access 的 primary_no_array_creation_expression 必須是 array_type 的值。For an array access, the primary_no_array_creation_expression of the element_access must be a value of an array_type. 此外,陣列存取的 argument_list 不能包含具名引數。 Argument_list 中的運算式數目必須與 array_type 的等級相同,而且每個運算式的類型必須是、、、 int
或,而且 uint
long
ulong
必須可以隱含地轉換成這些類型的一或多個。Furthermore, the argument_list of an array access is not allowed to contain named arguments.The number of expressions in the argument_list must be the same as the rank of the array_type, and each expression must be of type int
, uint
, long
, ulong
, or must be implicitly convertible to one or more of these types.
評估陣列存取的結果是陣列的元素類型變數,也就是 argument_list 中) 的運算式 (的值所選取的陣列元素 () s。The result of evaluating an array access is a variable of the element type of the array, namely the array element selected by the value(s) of the expression(s) in the argument_list.
表單存取的執行時間處理 P[A]
,其中 P
是 array_type 的 primary_no_array_creation_expression ,而 A
是一個 argument_list,其中包含下列步驟:The run-time processing of an array access of the form P[A]
, where P
is a primary_no_array_creation_expression of an array_type and A
is an argument_list, consists of the following steps:
P
會進行評估。P
is evaluated. 如果此評估造成例外狀況,則不會執行任何進一步的步驟。If this evaluation causes an exception, no further steps are executed.- Argument_list 的索引運算式會依序從左至右進行評估。The index expressions of the argument_list are evaluated in order, from left to right. 在評估每個索引運算式之後,會執行隱含轉換 (隱含 轉換) 為下列其中一種類型:
int
、uint
、long
、ulong
。Following evaluation of each index expression, an implicit conversion (Implicit conversions) to one of the following types is performed:int
,uint
,long
,ulong
. 此清單中的第一個類型會選擇隱含轉換存在。The first type in this list for which an implicit conversion exists is chosen. 比方說,如果索引運算式的型別為short
int
,則會執行隱含轉換,因為可能會將隱含轉換成short
int
和short
fromlong
。For instance, if the index expression is of typeshort
then an implicit conversion toint
is performed, since implicit conversions fromshort
toint
and fromshort
tolong
are possible. 如果索引運算式的評估或後續的隱含轉換造成例外狀況,則不會評估進一步的索引運算式,也不會執行任何進一步的步驟。If evaluation of an index expression or the subsequent implicit conversion causes an exception, then no further index expressions are evaluated and no further steps are executed. - 的值
P
會被檢查為有效。The value ofP
is checked to be valid. 如果的值P
為null
,則會擲回,System.NullReferenceException
且不會執行任何進一步的步驟。If the value ofP
isnull
, aSystem.NullReferenceException
is thrown and no further steps are executed. - 會根據所參考陣列實例的每個維度的實際界限,檢查 argument_list 中每個運算式的值
P
。The value of each expression in the argument_list is checked against the actual bounds of each dimension of the array instance referenced byP
. 如果有一或多個值超出範圍,則會擲回,System.IndexOutOfRangeException
且不會執行任何進一步的步驟。If one or more values are out of range, aSystem.IndexOutOfRangeException
is thrown and no further steps are executed. - 索引運算式 (s) 所提供的陣列元素位置會計算出來,而且這個位置會成為陣列存取的結果。The location of the array element given by the index expression(s) is computed, and this location becomes the result of the array access.
索引子存取Indexer access
針對索引子存取, element_access 的 primary_no_array_creation_expression 必須是類別、結構或介面型別的變數或值,而且此型別必須執行一或多個適用于 element_access 之 argument_list 的索引子。For an indexer access, the primary_no_array_creation_expression of the element_access must be a variable or value of a class, struct, or interface type, and this type must implement one or more indexers that are applicable with respect to the argument_list of the element_access.
形式的索引子存取的系結時間處理 P[A]
,其中 P
是類別、結構或介面型別的 primary_no_array_creation_expression T
,而 A
是 argument_list,包含下列步驟:The binding-time processing of an indexer access of the form P[A]
, where P
is a primary_no_array_creation_expression of a class, struct, or interface type T
, and A
is an argument_list, consists of the following steps:
- 由所提供的索引子集
T
。The set of indexers provided byT
is constructed. 此集合包含在中宣告的所有索引子,T
或的基底類型T
不是宣告override
,而且可以在目前的內容中存取 (成員存取) 。The set consists of all indexers declared inT
or a base type ofT
that are notoverride
declarations and are accessible in the current context (Member access). - 此集合會縮減為適用且不被其他索引子隱藏的索引子。The set is reduced to those indexers that are applicable and not hidden by other indexers. 下列規則會套用至集合中的每個索引子
S.I
,其中是用來宣告S
索引子的類型I
:The following rules are applied to each indexerS.I
in the set, whereS
is the type in which the indexerI
is declared:- 如果不適
I
用於A
(適用的函數成員) ,則I
會從集合中移除。IfI
is not applicable with respect toA
(Applicable function member), thenI
is removed from the set. - 如果
I
適用于 (適用的函式A
成員) ,則基底類型中宣告的所有索引子S
都會從集合中移除。IfI
is applicable with respect toA
(Applicable function member), then all indexers declared in a base type ofS
are removed from the set. - 如果
I
適用于 (適用的函式A
成員) ,而且S
是以外的類別型別object
,則會從集合中移除所有在介面中宣告的索引子。IfI
is applicable with respect toA
(Applicable function member) andS
is a class type other thanobject
, all indexers declared in an interface are removed from the set.
- 如果不適
- 如果產生的候選索引子集合是空的,則不存在任何適用的索引子,而且會發生系結階段錯誤。If the resulting set of candidate indexers is empty, then no applicable indexers exist, and a binding-time error occurs.
- 您可以使用多載解析規則的多 載解析規則來識別候選索引子集的最佳索引子。The best indexer of the set of candidate indexers is identified using the overload resolution rules of Overload resolution. 如果無法識別單一的最佳索引子,索引子存取就不明確,而且會發生系結階段錯誤。If a single best indexer cannot be identified, the indexer access is ambiguous, and a binding-time error occurs.
- Argument_list 的索引運算式會依序從左至右進行評估。The index expressions of the argument_list are evaluated in order, from left to right. 處理索引子存取的結果是分類為索引子存取的運算式。The result of processing the indexer access is an expression classified as an indexer access. 索引子存取運算式會參考上一個步驟中所決定的索引子,而且有相關聯的實例運算式
P
和相關聯的引數清單A
。The indexer access expression references the indexer determined in the step above, and has an associated instance expression ofP
and an associated argument list ofA
.
視使用的內容而定,索引子存取會造成 get 存取 子或索引子 set 存取 子的調用。Depending on the context in which it is used, an indexer access causes invocation of either the get accessor or the set accessor of the indexer. 如果索引子存取是指派的目標,則會叫用 set 存取 子,以 (簡單指派) 指派新值。If the indexer access is the target of an assignment, the set accessor is invoked to assign a new value (Simple assignment). 在其他所有情況下,則會叫用 get 存取 子,以取得目前值 () 的運算式值 。In all other cases, the get accessor is invoked to obtain the current value (Values of expressions).
這種存取權This access
This_access 包含保留字 this
。A this_access consists of the reserved word this
.
this_access
: 'this'
;
只有在實例的函式、實例方法或實例存取子的 區塊 中,才允許 this_access 。A this_access is permitted only in the block of an instance constructor, an instance method, or an instance accessor. 它具有下列其中一種意義:It has one of the following meanings:
- 當
this
在類別的實例函式內的 primary_expression 中使用時,它會分類為值。Whenthis
is used in a primary_expression within an instance constructor of a class, it is classified as a value. 值的類型是實例類型, (使用發生所在之類別的 實例類型) ,而值則是所要建立之物件的參考。The type of the value is the instance type (The instance type) of the class within which the usage occurs, and the value is a reference to the object being constructed. - 當
this
用於類別的實例方法或實例存取子內的 primary_expression 時,它會分類為值。Whenthis
is used in a primary_expression within an instance method or instance accessor of a class, it is classified as a value. 值的類型是實例類型, (使用發生所在之類別的 實例類型) ,而值則是對其叫用方法或存取子之物件的參考。The type of the value is the instance type (The instance type) of the class within which the usage occurs, and the value is a reference to the object for which the method or accessor was invoked. - 當
this
在結構的實例函式內的 primary_expression 中使用時,它會分類為變數。Whenthis
is used in a primary_expression within an instance constructor of a struct, it is classified as a variable. 變數的類型是實例類型, (使用發生所在之結構的 實例類型) ,而變數代表所要建立的結構。The type of the variable is the instance type (The instance type) of the struct within which the usage occurs, and the variable represents the struct being constructed.this
結構的實例函式的變數行為與結構類型的參數完全相同,特別是out
這表示必須在實例的每個執行路徑中明確地指派變數。Thethis
variable of an instance constructor of a struct behaves exactly the same as anout
parameter of the struct type—in particular, this means that the variable must be definitely assigned in every execution path of the instance constructor. - 當
this
在結構的實例方法或實例存取子內的 primary_expression 中使用時,它會分類為變數。Whenthis
is used in a primary_expression within an instance method or instance accessor of a struct, it is classified as a variable. 變數的類型是實例類型, (使用發生所在之結構的 實例類型) 。The type of the variable is the instance type (The instance type) of the struct within which the usage occurs.- 如果方法或存取子不是反覆運算器 (反覆運算 器) ,則
this
變數代表叫用方法或存取子的結構,而且行為與ref
結構類型的參數完全相同。If the method or accessor is not an iterator (Iterators), thethis
variable represents the struct for which the method or accessor was invoked, and behaves exactly the same as aref
parameter of the struct type. - 如果方法或存取子是反覆運算器,則
this
變數代表已叫用方法或存取子之結構的複本,而且行為與結構類型的值參數完全相同。If the method or accessor is an iterator, thethis
variable represents a copy of the struct for which the method or accessor was invoked, and behaves exactly the same as a value parameter of the struct type.
- 如果方法或存取子不是反覆運算器 (反覆運算 器) ,則
this
在 primary_expression 于上述內容以外的內容中使用,是編譯時期錯誤。Use of this
in a primary_expression in a context other than the ones listed above is a compile-time error. 尤其是,無法 this
在靜態方法、靜態屬性存取子或欄位宣告的 variable_initializer 中參考。In particular, it is not possible to refer to this
in a static method, a static property accessor, or in a variable_initializer of a field declaration.
基底存取Base access
Base_access 包含保留字, base
後面接著 " .
" 權杖和識別碼或以方括弧括住的 argument_list :A base_access consists of the reserved word base
followed by either a ".
" token and an identifier or an argument_list enclosed in square brackets:
base_access
: 'base' '.' identifier
| 'base' '[' expression_list ']'
;
Base_access 是用來存取基類成員,這些成員在目前的類別或結構中以類似的命名成員隱藏。A base_access is used to access base class members that are hidden by similarly named members in the current class or struct. 只有在實例的函式、實例方法或實例存取子的 區塊 中,才允許 base_access 。A base_access is permitted only in the block of an instance constructor, an instance method, or an instance accessor. base.I
發生于類別或結構時, I
必須表示該類別或結構的基類成員。When base.I
occurs in a class or struct, I
must denote a member of the base class of that class or struct. 同樣地, base[E]
在類別中發生時,適用的索引子必須存在於基類中。Likewise, when base[E]
occurs in a class, an applicable indexer must exist in the base class.
在系結時間,會將表單 base_access 運算式的 base.I
base[E]
評估方式與撰寫時的完全 ((B)this).I
相同 ((B)this)[E]
,其中 B
是發生結構的類別或結構的基類。At binding-time, base_access expressions of the form base.I
and base[E]
are evaluated exactly as if they were written ((B)this).I
and ((B)this)[E]
, where B
is the base class of the class or struct in which the construct occurs. 因此, base.I
和 base[E]
會對應至 this.I
和 this[E]
,但 this
會被視為基類的實例。Thus, base.I
and base[E]
correspond to this.I
and this[E]
, except this
is viewed as an instance of the base class.
當 base_access 參考 (方法、屬性或索引子) 的虛擬函式成員時,會決定在執行時間時要叫用的函式成員 (編譯時間檢查動態 多載解析) 變更。When a base_access references a virtual function member (a method, property, or indexer), the determination of which function member to invoke at run-time (Compile-time checking of dynamic overload resolution) is changed. 所叫用的函式成員是藉由尋找最常衍生的實 (虛擬方法) 的函 B
式 (成員,而不是相對於的執行時間類型 this
,如同在非基底存取) 中一般。The function member that is invoked is determined by finding the most derived implementation (Virtual methods) of the function member with respect to B
(instead of with respect to the run-time type of this
, as would be usual in a non-base access). 因此,在 override
virtual
函數成員的中, base_access 可以用來叫用繼承的函式成員實作為。Thus, within an override
of a virtual
function member, a base_access can be used to invoke the inherited implementation of the function member. 如果 base_access 所參考的函數成員是抽象的,則會發生系結階段錯誤。If the function member referenced by a base_access is abstract, a binding-time error occurs.
後置遞增和遞減運算子Postfix increment and decrement operators
post_increment_expression
: primary_expression '++'
;
post_decrement_expression
: primary_expression '--'
;
後置遞增或遞減運算的運算元必須是分類為變數、屬性存取或索引子存取的運算式。The operand of a postfix increment or decrement operation must be an expression classified as a variable, a property access, or an indexer access. 運算的結果是與運算元相同類型的值。The result of the operation is a value of the same type as the operand.
如果 primary_expression 具有編譯時間類型 dynamic
,則運算子會動態系結 (動態繫結) 、 post_increment_expression 或 post_decrement_expression 具有編譯時間類型, dynamic
而下列規則會在執行時間使用 primary_expression 的執行時間類型套用。If the primary_expression has the compile-time type dynamic
then the operator is dynamically bound (Dynamic binding), the post_increment_expression or post_decrement_expression has the compile-time type dynamic
and the following rules are applied at run-time using the run-time type of the primary_expression.
如果後置遞增或遞減運算的運算元是屬性或索引子存取,則屬性或索引子必須同時具有 get
和存取子 set
。If the operand of a postfix increment or decrement operation is a property or indexer access, the property or indexer must have both a get
and a set
accessor. 如果不是這種情況,就會發生系結階段錯誤。If this is not the case, a binding-time error occurs.
一元運算子多載解析 (一元運算子 多載解析) 適用于選取特定的運算子執行。Unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. 預先 ++
定義 --
的和運算子存在於下列類型:、、、、、、、、、、、 sbyte
byte
short
ushort
int
uint
long
ulong
char
float
double
decimal
和任何列舉類型。Predefined ++
and --
operators exist for the following types: sbyte
, byte
, short
, ushort
, int
, uint
, long
, ulong
, char
, float
, double
, decimal
, and any enum type. 預先定義的運算子會傳回將 ++
1 加入運算元所產生的值,而預先定義的運算子會傳回 --
從運算元減去1所產生的值。The predefined ++
operators return the value produced by adding 1 to the operand, and the predefined --
operators return the value produced by subtracting 1 from the operand. 在 checked
內容中,如果這個加法或減法的結果超出結果型別的範圍,且結果型別是整數型別或列舉型別, System.OverflowException
就會擲回。In a checked
context, if the result of this addition or subtraction is outside the range of the result type and the result type is an integral type or enum type, a System.OverflowException
is thrown.
表單的後置遞增或遞減作業的執行時間處理, x++
或是 x--
由下列步驟所組成:The run-time processing of a postfix increment or decrement operation of the form x++
or x--
consists of the following steps:
- 如果
x
分類為變數:Ifx
is classified as a variable:x
會評估以產生變數。x
is evaluated to produce the variable.- 的值
x
會儲存。The value ofx
is saved. - 使用已儲存的值
x
做為其引數來叫用選取的運算子。The selected operator is invoked with the saved value ofx
as its argument. - 運算子所傳回的值會儲存在評估所指定的位置
x
。The value returned by the operator is stored in the location given by the evaluation ofx
. - 的儲存值
x
會成為作業的結果。The saved value ofx
becomes the result of the operation.
- 如果
x
分類為屬性或索引子存取:Ifx
is classified as a property or indexer access:- 如果不是) ,實例運算式 (
x
static
,且如果x
是與相關聯的索引子存取) ,則會評估引數 (清單x
,且結果會用於後續get
和set
存取子調用。The instance expression (ifx
is notstatic
) and the argument list (ifx
is an indexer access) associated withx
are evaluated, and the results are used in the subsequentget
andset
accessor invocations. - 會叫用的
get
存取子x
,並儲存傳回的值。Theget
accessor ofx
is invoked and the returned value is saved. - 使用已儲存的值
x
做為其引數來叫用選取的運算子。The selected operator is invoked with the saved value ofx
as its argument. - 的
set
存取子x
會以運算子傳回的值做為其引數來叫用value
。Theset
accessor ofx
is invoked with the value returned by the operator as itsvalue
argument. - 的儲存值
x
會成為作業的結果。The saved value ofx
becomes the result of the operation.
- 如果不是) ,實例運算式 (
++
And --
運算子也支援前置詞標記法 (首碼遞增和遞減運算子) 。The ++
and --
operators also support prefix notation (Prefix increment and decrement operators). 或的結果通常是在作業 x++
x--
之前的值 x
,而或的結果 ++x
是作業之後的 --x
值 x
。Typically, the result of x++
or x--
is the value of x
before the operation, whereas the result of ++x
or --x
is the value of x
after the operation. 在任一種情況下, x
其本身在作業之後都具有相同的值。In either case, x
itself has the same value after the operation.
您 operator ++
operator --
可以使用後置或前置標記法來叫用或實作為。An operator ++
or operator --
implementation can be invoked using either postfix or prefix notation. 這兩種標記法不能有個別的運算子實現。It is not possible to have separate operator implementations for the two notations.
new 運算子The new operator
new
運算子用來建立類型的新實例。The new
operator is used to create new instances of types.
有三種形式的 new
運算式:There are three forms of new
expressions:
- 物件建立運算式可用來建立類別型別和實數值型別的新實例。Object creation expressions are used to create new instances of class types and value types.
- 陣列建立運算式可用來建立陣列類型的新實例。Array creation expressions are used to create new instances of array types.
- 委派建立運算式是用來建立委派類型的新實例。Delegate creation expressions are used to create new instances of delegate types.
new
運算子意指建立型別的實例,但不一定表示動態配置記憶體。The new
operator implies creation of an instance of a type, but does not necessarily imply dynamic allocation of memory. 尤其是實值型別的實例不需要額外的記憶體,就是它們所在的變數,而且當 new
用來建立實值型別的實例時,不會發生任何動態配置。In particular, instances of value types require no additional memory beyond the variables in which they reside, and no dynamic allocations occur when new
is used to create instances of value types.
物件建立運算式Object creation expressions
Object_creation_expression 用來建立 class_type 或 value_type 的新實例。An object_creation_expression is used to create a new instance of a class_type or a value_type.
object_creation_expression
: 'new' type '(' argument_list? ')' object_or_collection_initializer?
| 'new' type object_or_collection_initializer
;
object_or_collection_initializer
: object_initializer
| collection_initializer
;
Object_creation_expression 的 型 別必須是 class_type、 value_type 或 type_parameter。The type of an object_creation_expression must be a class_type, a value_type or a type_parameter. 此 類型 不能是 abstract
class_type。The type cannot be an abstract
class_type.
只有當 類型 為 class_type 或 struct_type 時,才允許選擇性的 argument_list (引數清單) 。The optional argument_list (Argument lists) is permitted only if the type is a class_type or a struct_type.
物件建立運算式可以省略函式引數清單,並在包含物件初始化運算式或集合初始化運算式時,括住括弧。An object creation expression can omit the constructor argument list and enclosing parentheses provided it includes an object initializer or collection initializer. 省略函式引數清單和封閉括弧相當於指定空的引數清單。Omitting the constructor argument list and enclosing parentheses is equivalent to specifying an empty argument list.
處理包含物件初始化運算式或集合初始化運算式的物件建立運算式包含第一次處理實例的函式,然後處理物件初始化運算式所指定的成員或元素初始化 (物件 初始化運算式) 或集合初始化運算式 (集合初始化 運算式) 。Processing of an object creation expression that includes an object initializer or collection initializer consists of first processing the instance constructor and then processing the member or element initializations specified by the object initializer (Object initializers) or collection initializer (Collection initializers).
如果選擇性 argument_list 中的任何引數具有編譯時間類型,則 dynamic
object_creation_expression 會動態系結 (動態繫結) ,而且在執行時間會使用具有編譯時間類型之 argument_list 引數的執行時間類型,套用下列規則 dynamic
。If any of the arguments in the optional argument_list has the compile-time type dynamic
then the object_creation_expression is dynamically bound (Dynamic binding) and the following rules are applied at run-time using the run-time type of those arguments of the argument_list that have the compile time type dynamic
. 不過,建立物件時,會依照動態多載 解析的編譯時間檢查所述,進行有限的編譯時間檢查。However, the object creation undergoes a limited compile time check as described in Compile-time checking of dynamic overload resolution.
表單 object_creation_expression 的系結時間處理 new T(A)
,其中 T
是 class_type 或 value_type ,而 A
是選擇性的 argument_list,包含下列步驟:The binding-time processing of an object_creation_expression of the form new T(A)
, where T
is a class_type or a value_type and A
is an optional argument_list, consists of the following steps:
- 如果
T
是 value_type 且A
不存在:IfT
is a value_type andA
is not present:- Object_creation_expression 是預設的函式呼叫。The object_creation_expression is a default constructor invocation. Object_creation_expression 的結果是類型的值,也就是在
T
T
system.object 類型中定義的預設值。The result of the object_creation_expression is a value of typeT
, namely the default value forT
as defined in The System.ValueType type.
- Object_creation_expression 是預設的函式呼叫。The object_creation_expression is a default constructor invocation. Object_creation_expression 的結果是類型的值,也就是在
- 否則,如果
T
是 type_parameter 且不A
存在:Otherwise, ifT
is a type_parameter andA
is not present:- 如果未指定任何實值型別條件約束或函式條件約束 (類型參數條件 約束)
T
,就會發生系結階段錯誤。If no value type constraint or constructor constraint (Type parameter constraints) has been specified forT
, a binding-time error occurs. - Object_creation_expression 的結果是型別參數已系結之執行時間類型的值,也就是叫用該型別的預設函式的結果。The result of the object_creation_expression is a value of the run-time type that the type parameter has been bound to, namely the result of invoking the default constructor of that type. 執行時間類型可以是參考型別或實值型別。The run-time type may be a reference type or a value type.
- 如果未指定任何實值型別條件約束或函式條件約束 (類型參數條件 約束)
- 否則,如果
T
是 class_type 或 struct_type:Otherwise, ifT
is a class_type or a struct_type:- 如果
T
是abstract
class_type,就會發生編譯時期錯誤。IfT
is anabstract
class_type, a compile-time error occurs. - 要叫用的實例函式是使用多載解析規則的多載解析規則來決定。The instance constructor to invoke is determined using the overload resolution rules of Overload resolution. 這組候選實例的函式是由中宣告的所有可存取的實例函式所組成,
T
這些都適用于A
(適用的函數成員) 。The set of candidate instance constructors consists of all accessible instance constructors declared inT
which are applicable with respect toA
(Applicable function member). 如果候選實例的函式集合是空的,或無法識別單一最佳實例的函式,則會發生系結階段錯誤。If the set of candidate instance constructors is empty, or if a single best instance constructor cannot be identified, a binding-time error occurs. - Object_creation_expression 的結果是類型的值,也就是叫用
T
上述步驟中所決定的實例函式所產生的值。The result of the object_creation_expression is a value of typeT
, namely the value produced by invoking the instance constructor determined in the step above.
- 如果
- 否則, object_creation_expression 無效,而且會發生系結階段錯誤。Otherwise, the object_creation_expression is invalid, and a binding-time error occurs.
即使 object_creation_expression 動態繫結,編譯時間類型仍是 T
。Even if the object_creation_expression is dynamically bound, the compile-time type is still T
.
表單 object_creation_expression 的執行時間處理 new T(A)
,其中 T
是 class_type 或 struct_type ,而 A
是選擇性的 argument_list,其中包含下列步驟:The run-time processing of an object_creation_expression of the form new T(A)
, where T
is class_type or a struct_type and A
is an optional argument_list, consists of the following steps:
- 如果
T
是 class_type:IfT
is a class_type:- 配置給類別的新實例
T
。A new instance of classT
is allocated. 如果沒有足夠的記憶體可配置新的實例,則會擲回,System.OutOfMemoryException
且不會執行任何進一步的步驟。If there is not enough memory available to allocate the new instance, aSystem.OutOfMemoryException
is thrown and no further steps are executed. - 新實例的所有欄位都會初始化為預設值 (預設值) 。All fields of the new instance are initialized to their default values (Default values).
- 根據函數成員調用的規則叫用實例的函式, (動態多載解析) 的編譯時期檢查 。The instance constructor is invoked according to the rules of function member invocation (Compile-time checking of dynamic overload resolution). 新配置之實例的參考會自動傳遞給實例的函式,而且可以在該函式內以形式存取實例
this
。A reference to the newly allocated instance is automatically passed to the instance constructor and the instance can be accessed from within that constructor asthis
.
- 配置給類別的新實例
- 如果
T
是 struct_type:IfT
is a struct_type:- 型別的實例
T
是藉由配置暫存區域變數所建立。An instance of typeT
is created by allocating a temporary local variable. 由於 struct_type 的實例函式必須將值明確指派給要建立之實例的每個欄位,因此不需要初始化暫存變數。Since an instance constructor of a struct_type is required to definitely assign a value to each field of the instance being created, no initialization of the temporary variable is necessary. - 根據函數成員調用的規則叫用實例的函式, (動態多載解析) 的編譯時期檢查 。The instance constructor is invoked according to the rules of function member invocation (Compile-time checking of dynamic overload resolution). 新配置之實例的參考會自動傳遞給實例的函式,而且可以在該函式內以形式存取實例
this
。A reference to the newly allocated instance is automatically passed to the instance constructor and the instance can be accessed from within that constructor asthis
.
- 型別的實例
物件初始設定式Object initializers
物件初始化運算式 會為物件的零或多個欄位、屬性或索引元素指定值。An object initializer specifies values for zero or more fields, properties or indexed elements of an object.
object_initializer
: '{' member_initializer_list? '}'
| '{' member_initializer_list ',' '}'
;
member_initializer_list
: member_initializer (',' member_initializer)*
;
member_initializer
: initializer_target '=' initializer_value
;
initializer_target
: identifier
| '[' argument_list ']'
;
initializer_value
: expression
| object_or_collection_initializer
;
物件初始化運算式是由一系列的成員初始化運算式所組成,並以和標記括住, {
}
並以逗號分隔。An object initializer consists of a sequence of member initializers, enclosed by {
and }
tokens and separated by commas. 每個 member_initializer 都會指定初始化的目標。Each member_initializer designates a target for the initialization. 識別碼 必須命名要初始化之物件的可存取欄位或屬性,而以方括弧括住的 argument_list 必須指定要初始化之物件上的可存取索引子引數。An identifier must name an accessible field or property of the object being initialized, whereas an argument_list enclosed in square brackets must specify arguments for an accessible indexer on the object being initialized. 物件初始化運算式針對相同的欄位或屬性包含一個以上的成員初始化運算式時,會發生錯誤。It is an error for an object initializer to include more than one member initializer for the same field or property.
每個 initializer_target 後面都會加上等號,以及運算式、物件初始化運算式或集合初始化運算式。Each initializer_target is followed by an equals sign and either an expression, an object initializer or a collection initializer. 物件初始化運算式內的運算式無法參考其正在初始化的新建立的物件。It is not possible for expressions within the object initializer to refer to the newly created object it is initializing.
成員初始化運算式,指定等號之後的運算式會以與指派 (簡單指派) 的相同方式處理。A member initializer that specifies an expression after the equals sign is processed in the same way as an assignment (Simple assignment) to the target.
成員初始化運算式,指定等號後面的物件初始化運算式是 嵌套物件初始化運算式,亦即内嵌物件的初始化。A member initializer that specifies an object initializer after the equals sign is a nested object initializer, i.e. an initialization of an embedded object. 將嵌套物件初始化運算式中的指派視為欄位或屬性成員的指派,而不是指派新值給欄位或屬性。Instead of assigning a new value to the field or property, the assignments in the nested object initializer are treated as assignments to members of the field or property. 您無法將嵌套物件初始化運算式套用至具有實數值型別的屬性,也無法套用至具有實數值型別的唯讀欄位。Nested object initializers cannot be applied to properties with a value type, or to read-only fields with a value type.
成員初始化運算式,會在等號之後指定集合初始化運算式為內嵌集合的初始化。A member initializer that specifies a collection initializer after the equals sign is an initialization of an embedded collection. 它不會將新的集合指派給目標欄位、屬性或索引子,而是會將初始化運算式中提供的專案加入至目標所參考的集合。Instead of assigning a new collection to the target field, property or indexer, the elements given in the initializer are added to the collection referenced by the target. 目標的集合類型必須符合 集合初始化運算式中所指定的需求。The target must be of a collection type that satisfies the requirements specified in Collection initializers.
索引初始化運算式的引數一律只會評估一次。The arguments to an index initializer will always be evaluated exactly once. 因此,即使引數最後不會使用 (例如,因為有空白的嵌套初始化運算式) ,所以會評估它們是否有副作用。Thus, even if the arguments end up never getting used (e.g. because of an empty nested initializer), they will be evaluated for their side effects.
下列類別代表具有兩個座標的點:The following class represents a point with two coordinates:
public class Point
{
int x, y;
public int X { get { return x; } set { x = value; } }
public int Y { get { return y; } set { y = value; } }
}
的實例 Point
可以建立和初始化,如下所示:An instance of Point
can be created and initialized as follows:
Point a = new Point { X = 0, Y = 1 };
其效果與which has the same effect as
Point __a = new Point();
__a.X = 0;
__a.Y = 1;
Point a = __a;
其中 __a
是其他隱藏且無法存取的暫存變數。where __a
is an otherwise invisible and inaccessible temporary variable. 下列類別代表從兩個點建立的矩形:The following class represents a rectangle created from two points:
public class Rectangle
{
Point p1, p2;
public Point P1 { get { return p1; } set { p1 = value; } }
public Point P2 { get { return p2; } set { p2 = value; } }
}
的實例 Rectangle
可以建立和初始化,如下所示:An instance of Rectangle
can be created and initialized as follows:
Rectangle r = new Rectangle {
P1 = new Point { X = 0, Y = 1 },
P2 = new Point { X = 2, Y = 3 }
};
其效果與which has the same effect as
Rectangle __r = new Rectangle();
Point __p1 = new Point();
__p1.X = 0;
__p1.Y = 1;
__r.P1 = __p1;
Point __p2 = new Point();
__p2.X = 2;
__p2.Y = 3;
__r.P2 = __p2;
Rectangle r = __r;
其中 __r
、 __p1
和 __p2
是不可見和無法存取的臨時變數。where __r
, __p1
and __p2
are temporary variables that are otherwise invisible and inaccessible.
If 的函式會配置 Rectangle
兩個內嵌的 Point
實例If Rectangle
's constructor allocates the two embedded Point
instances
public class Rectangle
{
Point p1 = new Point();
Point p2 = new Point();
public Point P1 { get { return p1; } }
public Point P2 { get { return p2; } }
}
下列結構可以用來初始化內嵌的實例, Point
而不是指派新的實例:the following construct can be used to initialize the embedded Point
instances instead of assigning new instances:
Rectangle r = new Rectangle {
P1 = { X = 0, Y = 1 },
P2 = { X = 2, Y = 3 }
};
其效果與which has the same effect as
Rectangle __r = new Rectangle();
__r.P1.X = 0;
__r.P1.Y = 1;
__r.P2.X = 2;
__r.P2.Y = 3;
Rectangle r = __r;
假設有適當的 C 定義,則下列範例:Given an appropriate definition of C, the following example:
var c = new C {
x = true,
y = { a = "Hello" },
z = { 1, 2, 3 },
["x"] = 5,
[0,0] = { "a", "b" },
[1,2] = {}
};
相當於這一系列的指派:is equivalent to this series of assignments:
C __c = new C();
__c.x = true;
__c.y.a = "Hello";
__c.z.Add(1);
__c.z.Add(2);
__c.z.Add(3);
string __i1 = "x";
__c[__i1] = 5;
int __i2 = 0, __i3 = 0;
__c[__i2,__i3].Add("a");
__c[__i2,__i3].Add("b");
int __i4 = 1, __i5 = 2;
var c = __c;
其中 __c
,會產生不可見且無法存取原始程式碼的變數。where __c
, etc., are generated variables that are invisible and inaccessible to the source code. 請注意,的引數 [0,0]
只會評估一次,而的引數會 [1,2]
評估一次,即使從未使用過也一樣。Note that the arguments for [0,0]
are evaluated only once, and the arguments for [1,2]
are evaluated once even though they are never used.
集合初始設定式Collection initializers
集合初始化運算式會指定集合的元素。A collection initializer specifies the elements of a collection.
collection_initializer
: '{' element_initializer_list '}'
| '{' element_initializer_list ',' '}'
;
element_initializer_list
: element_initializer (',' element_initializer)*
;
element_initializer
: non_assignment_expression
| '{' expression_list '}'
;
expression_list
: expression (',' expression)*
;
集合初始化運算式是由一系列的元素初始化運算式所組成,並以和標記括住, {
}
並以逗號分隔。A collection initializer consists of a sequence of element initializers, enclosed by {
and }
tokens and separated by commas. 每個專案初始化運算式會指定要加入至要初始化之集合物件的專案,並包含以和標記括住的運算式清單, {
}
並以逗號分隔。Each element initializer specifies an element to be added to the collection object being initialized, and consists of a list of expressions enclosed by {
and }
tokens and separated by commas. 單一運算式專案初始化運算式可以不使用大括弧來撰寫,但之後也不能是指派運算式,以避免與成員初始化運算式混淆。A single-expression element initializer can be written without braces, but cannot then be an assignment expression, to avoid ambiguity with member initializers. Non_assignment_expression 生產是在 expression中定義。The non_assignment_expression production is defined in Expression.
以下是包含集合初始化運算式的物件建立運算式範例:The following is an example of an object creation expression that includes a collection initializer:
List<int> digits = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
要套用集合初始化運算式的集合物件,必須是可執行檔型別, System.Collections.IEnumerable
或發生編譯時期錯誤。The collection object to which a collection initializer is applied must be of a type that implements System.Collections.IEnumerable
or a compile-time error occurs. 集合初始化運算式會針對每個指定的專案, Add
使用專案初始化運算式的運算式清單做為引數清單,在目標物件上叫用方法,並為每個調用套用一般成員查閱和多載解析。For each specified element in order, the collection initializer invokes an Add
method on the target object with the expression list of the element initializer as argument list, applying normal member lookup and overload resolution for each invocation. 因此,collection 物件必須有適用的實例或擴充方法,且 Add
每個專案初始化運算式都有名稱。Thus, the collection object must have an applicable instance or extension method with the name Add
for each element initializer.
下列類別代表具有名稱和電話號碼清單的連絡人:The following class represents a contact with a name and a list of phone numbers:
public class Contact
{
string name;
List<string> phoneNumbers = new List<string>();
public string Name { get { return name; } set { name = value; } }
public List<string> PhoneNumbers { get { return phoneNumbers; } }
}
List<Contact>
可以建立和初始化,如下所示:A List<Contact>
can be created and initialized as follows:
var contacts = new List<Contact> {
new Contact {
Name = "Chris Smith",
PhoneNumbers = { "206-555-0101", "425-882-8080" }
},
new Contact {
Name = "Bob Harris",
PhoneNumbers = { "650-555-0199" }
}
};
其效果與which has the same effect as
var __clist = new List<Contact>();
Contact __c1 = new Contact();
__c1.Name = "Chris Smith";
__c1.PhoneNumbers.Add("206-555-0101");
__c1.PhoneNumbers.Add("425-882-8080");
__clist.Add(__c1);
Contact __c2 = new Contact();
__c2.Name = "Bob Harris";
__c2.PhoneNumbers.Add("650-555-0199");
__clist.Add(__c2);
var contacts = __clist;
其中 __clist
、 __c1
和 __c2
是不可見和無法存取的臨時變數。where __clist
, __c1
and __c2
are temporary variables that are otherwise invisible and inaccessible.
陣列建立運算式Array creation expressions
Array_creation_expression 用來建立 array_type 的新實例。An array_creation_expression is used to create a new instance of an array_type.
array_creation_expression
: 'new' non_array_type '[' expression_list ']' rank_specifier* array_initializer?
| 'new' array_type array_initializer
| 'new' rank_specifier array_initializer
;
第一個表單的陣列建立運算式會配置從運算式清單中刪除每個個別運算式所產生之類型的陣列實例。An array creation expression of the first form allocates an array instance of the type that results from deleting each of the individual expressions from the expression list. 例如,陣列建立運算式會 new int[10,20]
產生型別的陣列實例 int[,]
,而陣列建立運算式會 new int[10][,]
產生型別的陣列 int[][,]
。For example, the array creation expression new int[10,20]
produces an array instance of type int[,]
, and the array creation expression new int[10][,]
produces an array of type int[][,]
. 運算式清單中的每個運算式都必須是 int
、 uint
、 long
或類型,或是可 ulong
隱含轉換成這些類型的一或多個。Each expression in the expression list must be of type int
, uint
, long
, or ulong
, or implicitly convertible to one or more of these types. 每個運算式的值會決定新配置陣列實例中對應維度的長度。The value of each expression determines the length of the corresponding dimension in the newly allocated array instance. 因為陣列維度的長度必須是非負值,所以在運算式清單中有一個具有負值的 constant_expression 是編譯時期錯誤。Since the length of an array dimension must be nonnegative, it is a compile-time error to have a constant_expression with a negative value in the expression list.
除了在 unsafe 內容中 (不安全 的內容) 之外,不會指定陣列的配置。Except in an unsafe context (Unsafe contexts), the layout of arrays is unspecified.
如果第一個表單的陣列建立運算式包含陣列初始化運算式,則運算式清單中的每個運算式都必須是常數,而且運算式清單所指定的順位和維度長度必須符合陣列初始化運算式的運算式。If an array creation expression of the first form includes an array initializer, each expression in the expression list must be a constant and the rank and dimension lengths specified by the expression list must match those of the array initializer.
在第二或第三個表單的陣列建立運算式中,指定之陣列類型或等級規範的等級必須符合陣列初始化運算式的次序。In an array creation expression of the second or third form, the rank of the specified array type or rank specifier must match that of the array initializer. 個別的維度長度是從陣列初始化運算式的每個對應嵌套層級中的元素數目推斷而來。The individual dimension lengths are inferred from the number of elements in each of the corresponding nesting levels of the array initializer. 因此,運算式Thus, the expression
new int[,] {{0, 1}, {2, 3}, {4, 5}}
完全對應至exactly corresponds to
new int[3, 2] {{0, 1}, {2, 3}, {4, 5}}
第三個表單的陣列建立運算式稱為「隱含類型陣列建立運算式 _」。An array creation expression of the third form is referred to as an *implicitly typed array creation expression _. 它類似于第二個表單,不同之處在于陣列的元素類型未明確指定,但卻決定為最佳的一般型別, (在陣列初始化運算式中尋找一組運算式) 的 最佳一般 類型。It is similar to the second form, except that the element type of the array is not explicitly given, but determined as the best common type (Finding the best common type of a set of expressions) of the set of expressions in the array initializer. 若為多維度陣列,也就是 _rank_specifier * 至少包含一個逗號的運算式,此集合會包含在嵌套 array_initializer s 中找到的所有 運算式。For a multidimensional array, i.e., one where the _rank_specifier* contains at least one comma, this set comprises all expression s found in nested array_initializer s.
陣列初始化運算式會在 陣列初始化運算式中進一步說明。Array initializers are described further in Array initializers.
評估陣列建立運算式的結果會分類為值,亦即新配置陣列實例的參考。The result of evaluating an array creation expression is classified as a value, namely a reference to the newly allocated array instance. 陣列建立運算式的執行時間處理是由下列步驟所組成:The run-time processing of an array creation expression consists of the following steps:
- Expression_list 的維度長度運算式會依序從左至右進行評估。The dimension length expressions of the expression_list are evaluated in order, from left to right. 在評估每個運算式之後,會執行隱含轉換 (隱含 轉換) 為下列其中一種類型:
int
、uint
、long
、ulong
。Following evaluation of each expression, an implicit conversion (Implicit conversions) to one of the following types is performed:int
,uint
,long
,ulong
. 此清單中的第一個類型會選擇隱含轉換存在。The first type in this list for which an implicit conversion exists is chosen. 如果運算式的評估或後續的隱含轉換造成例外狀況,則不會評估任何進一步的運算式,也不會執行任何進一步的步驟。If evaluation of an expression or the subsequent implicit conversion causes an exception, then no further expressions are evaluated and no further steps are executed. - 維度長度的計算值會依照下列方式進行驗證。The computed values for the dimension lengths are validated as follows. 如果有一或多個值小於零,則會擲回,
System.OverflowException
且不會執行任何進一步的步驟。If one or more of the values are less than zero, aSystem.OverflowException
is thrown and no further steps are executed. - 配置具有給定維度長度的陣列實例。An array instance with the given dimension lengths is allocated. 如果沒有足夠的記憶體可配置新的實例,則會擲回,
System.OutOfMemoryException
且不會執行任何進一步的步驟。If there is not enough memory available to allocate the new instance, aSystem.OutOfMemoryException
is thrown and no further steps are executed. - 新陣列實例的所有元素都會初始化為預設值 (預設值) 。All elements of the new array instance are initialized to their default values (Default values).
- 如果陣列建立運算式包含陣列初始化運算式,則會評估陣列初始化運算式中的每個運算式,並將其指派給其對應的陣列元素。If the array creation expression contains an array initializer, then each expression in the array initializer is evaluated and assigned to its corresponding array element. 評估和指派會依照運算式在陣列初始化運算式中的寫入順序來執行,換句話說,專案會以遞增的索引順序初始化,而最右邊的維度會先遞增。The evaluations and assignments are performed in the order the expressions are written in the array initializer—in other words, elements are initialized in increasing index order, with the rightmost dimension increasing first. 如果指定運算式的評估或對應的陣列元素的後續指派造成例外狀況,則不會 (進一步的元素初始化,其餘的元素則會) 其預設值。If evaluation of a given expression or the subsequent assignment to the corresponding array element causes an exception, then no further elements are initialized (and the remaining elements will thus have their default values).
陣列建立運算式允許具現化陣列型別元素的陣列,但是這類陣列的元素必須以手動方式初始化。An array creation expression permits instantiation of an array with elements of an array type, but the elements of such an array must be manually initialized. 例如,語句For example, the statement
int[][] a = new int[100][];
建立具有類型100元素的一維陣列 int[]
。creates a single-dimensional array with 100 elements of type int[]
. 每個元素的初始值為 null
。The initial value of each element is null
. 相同的陣列建立運算式也不可能同時具現化子陣列和語句It is not possible for the same array creation expression to also instantiate the sub-arrays, and the statement
int[][] a = new int[100][5]; // Error
導致編譯階段錯誤。results in a compile-time error. 子陣列的具現化必須改為手動執行,如下所示:Instantiation of the sub-arrays must instead be performed manually, as in
int[][] a = new int[100][];
for (int i = 0; i < 100; i++) a[i] = new int[5];
當陣列陣列有「矩形」圖形時,也就是當子陣列的長度都相同時,使用多維度陣列會更有效率。When an array of arrays has a "rectangular" shape, that is when the sub-arrays are all of the same length, it is more efficient to use a multi-dimensional array. 在上述範例中,陣列陣列的具現化會建立101物件—一種外部陣列和100子陣列。In the example above, instantiation of the array of arrays creates 101 objects—one outer array and 100 sub-arrays. 相反地,In contrast,
int[,] = new int[100, 5];
只建立單一物件、二維陣列,並在單一語句中完成配置。creates only a single object, a two-dimensional array, and accomplishes the allocation in a single statement.
以下是隱含類型陣列建立運算式的範例:The following are examples of implicitly typed array creation expressions:
var a = new[] { 1, 10, 100, 1000 }; // int[]
var b = new[] { 1, 1.5, 2, 2.5 }; // double[]
var c = new[,] { { "hello", null }, { "world", "!" } }; // string[,]
var d = new[] { 1, "one", 2, "two" }; // Error
最後一個運算式會導致編譯時期錯誤,因為兩者都不能 int
string
隱含地轉換成另一個,所以沒有最佳的一般類型。The last expression causes a compile-time error because neither int
nor string
is implicitly convertible to the other, and so there is no best common type. 在此情況下,必須使用明確類型的陣列建立運算式,例如將型別指定為 object[]
。An explicitly typed array creation expression must be used in this case, for example specifying the type to be object[]
. 或者,您可以將其中一個專案轉換成通用基底類型,然後再成為推斷的元素類型。Alternatively, one of the elements can be cast to a common base type, which would then become the inferred element type.
隱含型別陣列建立運算式可以與匿名物件初始化運算式結合 (匿名物件建立運算式 ,) 建立匿名型別的資料結構。Implicitly typed array creation expressions can be combined with anonymous object initializers (Anonymous object creation expressions) to create anonymously typed data structures. 例如:For example:
var contacts = new[] {
new {
Name = "Chris Smith",
PhoneNumbers = new[] { "206-555-0101", "425-882-8080" }
},
new {
Name = "Bob Harris",
PhoneNumbers = new[] { "650-555-0199" }
}
};
委派建立運算式Delegate creation expressions
Delegate_creation_expression 用來建立 delegate_type 的新實例。A delegate_creation_expression is used to create a new instance of a delegate_type.
delegate_creation_expression
: 'new' delegate_type '(' expression ')'
;
委派建立運算式的引數必須是方法群組、匿名函數或編譯時間類型 dynamic
或 delegate_type 的值。The argument of a delegate creation expression must be a method group, an anonymous function or a value of either the compile time type dynamic
or a delegate_type. 如果引數是方法群組,它會識別方法,並針對實例方法識別要建立委派的物件。If the argument is a method group, it identifies the method and, for an instance method, the object for which to create a delegate. 如果引數是匿名函式,它會直接定義委派目標的參數和方法主體。If the argument is an anonymous function it directly defines the parameters and method body of the delegate target. 如果引數是值,它會識別要建立複本的委派實例。If the argument is a value it identifies a delegate instance of which to create a copy.
如果 運算式 具有編譯時間類型 dynamic
,則 delegate_creation_expression 會動態系結 (動態繫結) ,且下列規則會在執行時間使用 運算式 的執行時間類型來套用。If the expression has the compile-time type dynamic
, the delegate_creation_expression is dynamically bound (Dynamic binding), and the rules below are applied at run-time using the run-time type of the expression. 否則會在編譯時期套用規則。Otherwise the rules are applied at compile-time.
表單 delegate_creation_expression 的系結時間處理 new D(E)
(其中 D
是 delegate_type ,而 E
是 運算式),包含下列步驟:The binding-time processing of a delegate_creation_expression of the form new D(E)
, where D
is a delegate_type and E
is an expression, consists of the following steps:
- 如果
E
是方法群組,則會使用與方法群組轉換相同的方式來處理委派建立運算式 (方法群組 轉換) 從轉換E
為D
。IfE
is a method group, the delegate creation expression is processed in the same way as a method group conversion (Method group conversions) fromE
toD
. - 如果
E
是匿名函式,則會使用與匿名函式轉換相同的方式來處理委派建立運算式 (從) 到的 匿名 函式轉換E
D
。IfE
is an anonymous function, the delegate creation expression is processed in the same way as an anonymous function conversion (Anonymous function conversions) fromE
toD
. - 如果
E
是值,就E
必須與) 的 委派 宣告 (相容,D
而且結果會參考與D
相同的調用清單所建立之新建立的委派型別E
。IfE
is a value,E
must be compatible (Delegate declarations) withD
, and the result is a reference to a newly created delegate of typeD
that refers to the same invocation list asE
. 如果E
與不相容D
,就會發生編譯時期錯誤。IfE
is not compatible withD
, a compile-time error occurs.
表單 delegate_creation_expression 的執行時間處理 new D(E)
(其中 D
是 delegate_type ,而 E
是 運算式),包含下列步驟:The run-time processing of a delegate_creation_expression of the form new D(E)
, where D
is a delegate_type and E
is an expression, consists of the following steps:
- 如果
E
是方法群組,則會將委派建立運算式評估為方法群組轉換, (從) 至的 方法群組 轉換E
D
。IfE
is a method group, the delegate creation expression is evaluated as a method group conversion (Method group conversions) fromE
toD
. - 如果
E
是匿名函式,則會將委派建立評估為的匿名函式轉換,E
D
) (匿名 函數轉換。IfE
is an anonymous function, the delegate creation is evaluated as an anonymous function conversion fromE
toD
(Anonymous function conversions). - 如果
E
是 delegate_type 的值:IfE
is a value of a delegate_type:E
會進行評估。E
is evaluated. 如果此評估造成例外狀況,則不會執行任何進一步的步驟。If this evaluation causes an exception, no further steps are executed.- 如果的值
E
為null
,則會擲回,System.NullReferenceException
且不會執行任何進一步的步驟。If the value ofE
isnull
, aSystem.NullReferenceException
is thrown and no further steps are executed. - 配置委派類型的新實例
D
。A new instance of the delegate typeD
is allocated. 如果沒有足夠的記憶體可配置新的實例,則會擲回,System.OutOfMemoryException
且不會執行任何進一步的步驟。If there is not enough memory available to allocate the new instance, aSystem.OutOfMemoryException
is thrown and no further steps are executed. - 新的委派實例初始化時,所使用的調用清單與提供的委派實例相同
E
。The new delegate instance is initialized with the same invocation list as the delegate instance given byE
.
委派的調用清單是在委派具現化時決定的,然後在委派的整個存留期維持不變。The invocation list of a delegate is determined when the delegate is instantiated and then remains constant for the entire lifetime of the delegate. 換句話說,建立委派之後,就無法變更該委派的目標可呼叫實體。In other words, it is not possible to change the target callable entities of a delegate once it has been created. 當結合兩個委派,或從另一個 (委派 宣告中移除一個委派時) ,會有一個新的委派結果;沒有任何現有的委派已變更其內容。When two delegates are combined or one is removed from another (Delegate declarations), a new delegate results; no existing delegate has its contents changed.
您無法建立參考屬性、索引子、使用者定義的運算子、實例的函式、函式或靜態函式的委派。It is not possible to create a delegate that refers to a property, indexer, user-defined operator, instance constructor, destructor, or static constructor.
如上所述,從方法群組建立委派時,委派的型式參數清單和傳回型別會決定要選取的多載方法。As described above, when a delegate is created from a method group, the formal parameter list and return type of the delegate determine which of the overloaded methods to select. 在範例中In the example
delegate double DoubleFunc(double x);
class A
{
DoubleFunc f = new DoubleFunc(Square);
static float Square(float x) {
return x * x;
}
static double Square(double x) {
return x * x;
}
}
此 A.f
欄位會使用參考第二個方法的委派來初始化, Square
因為該方法完全符合的型式參數清單和傳回型別 DoubleFunc
。the A.f
field is initialized with a delegate that refers to the second Square
method because that method exactly matches the formal parameter list and return type of DoubleFunc
. 如果有第二個 Square
方法不存在,就會發生編譯時期錯誤。Had the second Square
method not been present, a compile-time error would have occurred.
匿名物件建立運算式Anonymous object creation expressions
Anonymous_object_creation_expression 用來建立匿名型別的物件。An anonymous_object_creation_expression is used to create an object of an anonymous type.
anonymous_object_creation_expression
: 'new' anonymous_object_initializer
;
anonymous_object_initializer
: '{' member_declarator_list? '}'
| '{' member_declarator_list ',' '}'
;
member_declarator_list
: member_declarator (',' member_declarator)*
;
member_declarator
: simple_name
| member_access
| base_access
| null_conditional_member_access
| identifier '=' expression
;
匿名物件初始化運算式會宣告匿名型別,並傳回該型別的實例。An anonymous object initializer declares an anonymous type and returns an instance of that type. 匿名型別是直接繼承自的無型別的類別型別 object
。An anonymous type is a nameless class type that inherits directly from object
. 匿名型別的成員是從匿名物件初始化運算式(用來建立類型的實例)推斷而來的唯讀屬性序列。The members of an anonymous type are a sequence of read-only properties inferred from the anonymous object initializer used to create an instance of the type. 具體而言,就是表單的匿名物件初始化運算式Specifically, an anonymous object initializer of the form
new { p1 = e1, p2 = e2, ..., pn = en }
宣告格式的匿名型別declares an anonymous type of the form
class __Anonymous1
{
private readonly T1 f1;
private readonly T2 f2;
...
private readonly Tn fn;
public __Anonymous1(T1 a1, T2 a2, ..., Tn an) {
f1 = a1;
f2 = a2;
...
fn = an;
}
public T1 p1 { get { return f1; } }
public T2 p2 { get { return f2; } }
...
public Tn pn { get { return fn; } }
public override bool Equals(object __o) { ... }
public override int GetHashCode() { ... }
}
其中每個 Tx
都是對應運算式的類型 ex
。where each Tx
is the type of the corresponding expression ex
. Member_declarator 中使用的運算式必須有型別。The expression used in a member_declarator must have a type. 因此, member_declarator 中的運算式為 null 或匿名函式時,就會發生編譯時期錯誤。Thus, it is a compile-time error for an expression in a member_declarator to be null or an anonymous function. 它也是一個編譯時期錯誤,讓運算式具有不安全的型別。It is also a compile-time error for the expression to have an unsafe type.
編譯器會自動產生匿名型別的名稱以及其方法的參數, Equals
而且不能在程式文字中參考。The names of an anonymous type and of the parameter to its Equals
method are automatically generated by the compiler and cannot be referenced in program text.
在相同的程式中,兩個以相同順序指定相同名稱和編譯時間類型之屬性順序的匿名物件初始化運算式,將會產生相同匿名型別的實例。Within the same program, two anonymous object initializers that specify a sequence of properties of the same names and compile-time types in the same order will produce instances of the same anonymous type.
在範例中In the example
var p1 = new { Name = "Lawnmower", Price = 495.00 };
var p2 = new { Name = "Shovel", Price = 26.95 };
p1 = p2;
因為 p1
和 p2
是相同的匿名型別,所以允許最後一行上的指派。the assignment on the last line is permitted because p1
and p2
are of the same anonymous type.
Equals
GetHashcode
匿名型別上的和方法會覆寫繼承自的方法, object
並且會根據屬性的和來定義 Equals
GetHashcode
,如此一來,只有在所有屬性都相等時,相同匿名型別的兩個實例才會相等。The Equals
and GetHashcode
methods on anonymous types override the methods inherited from object
, and are defined in terms of the Equals
and GetHashcode
of the properties, so that two instances of the same anonymous type are equal if and only if all their properties are equal.
成員宣告子可以縮寫為簡單名稱 (類型推斷) 、成員存取 (動態多載 解析) 的編譯時期檢查 、基底存取 (基底存取) ,或 null 條件成員存取 (null 條件運算式作為投影初始化運算式) 。A member declarator can be abbreviated to a simple name (Type inference), a member access (Compile-time checking of dynamic overload resolution), a base access (Base access) or a null-conditional member access (Null-conditional expressions as projection initializers). 這稱為 投射初始化運算式 ,而且是的宣告和指派給相同名稱之屬性的速記。This is called a projection initializer and is shorthand for a declaration of and assignment to a property with the same name. 具體而言,表單的成員宣告子Specifically, member declarators of the forms
identifier
expr.identifier
分別相當於下列各項:are precisely equivalent to the following, respectively:
identifier = identifier
identifier = expr.identifier
因此,在投射初始化運算式中, 識別碼 會同時選取值以及指派值的欄位或屬性。Thus, in a projection initializer the identifier selects both the value and the field or property to which the value is assigned. 直覺來說,投射初始化運算式專案不只是值,也是值的名稱。Intuitively, a projection initializer projects not just a value, but also the name of the value.
Typeof 運算子The typeof operator
typeof
運算子用來取得 System.Type
類型的物件。The typeof
operator is used to obtain the System.Type
object for a type.
typeof_expression
: 'typeof' '(' type ')'
| 'typeof' '(' unbound_type_name ')'
| 'typeof' '(' 'void' ')'
;
unbound_type_name
: identifier generic_dimension_specifier?
| identifier '::' identifier generic_dimension_specifier?
| unbound_type_name '.' identifier generic_dimension_specifier?
;
generic_dimension_specifier
: '<' comma* '>'
;
comma
: ','
;
Typeof_expression 的第一種形式是由 typeof
關鍵字後面加上括弧的 型 別所組成。The first form of typeof_expression consists of a typeof
keyword followed by a parenthesized type. 此表單運算式的結果是所 System.Type
指定類型的物件。The result of an expression of this form is the System.Type
object for the indicated type. System.Type
任何指定的類型只有一個物件。There is only one System.Type
object for any given type. 這表示針對型別 T
, typeof(T) == typeof(T)
一律為 true。This means that for a type T
, typeof(T) == typeof(T)
is always true. 類型 不可為 dynamic
。The type cannot be dynamic
.
第二種形式的 typeof_expression 是由 typeof
關鍵字後面加上括弧的 unbound_type_name 所組成。The second form of typeof_expression consists of a typeof
keyword followed by a parenthesized unbound_type_name. Unbound_type_name 與 Type_name (命名空間和類型) 名稱非常類似,不同之處在于 unbound_type_name 包含 generic_dimension_specifier 包含 type_name 的 type_argument_list。 An unbound_type_name is very similar to a type_name (Namespace and type names) except that an unbound_type_name contains generic_dimension_specifier s where a type_name contains type_argument_list s. 當 typeof_expression 的運算元是符合 unbound_type_name 和 type_name 之文法的標記序列時(亦即,當它不包含 generic_dimension_specifier 或 type_argument_list 時),會將標記序列視為 type_name。When the operand of a typeof_expression is a sequence of tokens that satisfies the grammars of both unbound_type_name and type_name, namely when it contains neither a generic_dimension_specifier nor a type_argument_list, the sequence of tokens is considered to be a type_name. Unbound_type_name 的意義會依照下列方式決定:The meaning of an unbound_type_name is determined as follows:
- 藉由將每個 generic_dimension_specifier 取代為
object
每個 type_argument 都有相同數目的逗號和關鍵字,以將每個 type_argument_list 轉換成 type_name。Convert the sequence of tokens to a type_name by replacing each generic_dimension_specifier with a type_argument_list having the same number of commas and the keywordobject
as each type_argument. - 評估產生的 type_name,同時忽略所有類型參數條件約束。Evaluate the resulting type_name, while ignoring all type parameter constraints.
- Unbound_type_name 會解析為未系結的泛型型別, (系結 和未系結的型別) )相關聯。The unbound_type_name resolves to the unbound generic type associated with the resulting constructed type (Bound and unbound types).
Typeof_expression 的結果是產生之未系結 System.Type
泛型型別的物件。The result of the typeof_expression is the System.Type
object for the resulting unbound generic type.
第三種形式的 typeof_expression 是由 typeof
關鍵字後面加上括弧的關鍵字所組成 void
。The third form of typeof_expression consists of a typeof
keyword followed by a parenthesized void
keyword. 此表單的運算式結果是 System.Type
代表沒有類型的物件。The result of an expression of this form is the System.Type
object that represents the absence of a type. 所傳回的類型物件與 typeof(void)
針對任何類型所傳回的類型物件不同。The type object returned by typeof(void)
is distinct from the type object returned for any type. 這個特殊類型物件適用于允許在語言中反映方法的類別庫,而這些方法希望有方法來表示具有實例之任何方法的傳回類型,包括 void 方法 System.Type
。This special type object is useful in class libraries that allow reflection onto methods in the language, where those methods wish to have a way to represent the return type of any method, including void methods, with an instance of System.Type
.
typeof
運算子可用於類型參數。The typeof
operator can be used on a type parameter. 結果是系結 System.Type
至型別參數之執行時間類型的物件。The result is the System.Type
object for the run-time type that was bound to the type parameter. typeof
運算子也可以用於已建立的型別或未系結的泛型型別, (系結和未系結的類型) 。The typeof
operator can also be used on a constructed type or an unbound generic type (Bound and unbound types). 未系結 System.Type
泛型型別的物件與 System.Type
實例類型的物件不同。The System.Type
object for an unbound generic type is not the same as the System.Type
object of the instance type. 實例型別在執行時間一律是封閉的結構化型別,因此它的 System.Type
物件取決於使用中的執行時間型別引數,而未系結的泛型型別則沒有型別引數。The instance type is always a closed constructed type at run-time so its System.Type
object depends on the run-time type arguments in use, while the unbound generic type has no type arguments.
範例The example
using System;
class X<T>
{
public static void PrintTypes() {
Type[] t = {
typeof(int),
typeof(System.Int32),
typeof(string),
typeof(double[]),
typeof(void),
typeof(T),
typeof(X<T>),
typeof(X<X<T>>),
typeof(X<>)
};
for (int i = 0; i < t.Length; i++) {
Console.WriteLine(t[i]);
}
}
}
class Test
{
static void Main() {
X<int>.PrintTypes();
}
}
產生下列輸出:produces the following output:
System.Int32
System.Int32
System.String
System.Double[]
System.Void
System.Int32
X`1[System.Int32]
X`1[X`1[System.Int32]]
X`1[T]
請注意, int
和 System.Int32
是相同的類型。Note that int
and System.Int32
are the same type.
另請注意,的結果 typeof(X<>)
不會相依于型別引數,而是的結果 typeof(X<T>)
。Also note that the result of typeof(X<>)
does not depend on the type argument but the result of typeof(X<T>)
does.
checked 和 unchecked 運算子The checked and unchecked operators
checked
和 unchecked
運算子用來控制整數型別算數運算和轉換的 溢位檢查內容。The checked
and unchecked
operators are used to control the overflow checking context for integral-type arithmetic operations and conversions.
checked_expression
: 'checked' '(' expression ')'
;
unchecked_expression
: 'unchecked' '(' expression ')'
;
checked
運算子會評估已檢查內容中的包含運算式,而 unchecked
運算子會在未檢查的內容中評估包含的運算式。The checked
operator evaluates the contained expression in a checked context, and the unchecked
operator evaluates the contained expression in an unchecked context. Checked_expression 或 unchecked_expression 完全對應至 parenthesized_expression (括弧內的 運算式) ,但包含的運算式會在指定的溢位檢查內容中進行評估。A checked_expression or unchecked_expression corresponds exactly to a parenthesized_expression (Parenthesized expressions), except that the contained expression is evaluated in the given overflow checking context.
溢位檢查內容也可以透過 checked
和語句來控制, unchecked
(checked 和 unchecked 語句) 。The overflow checking context can also be controlled through the checked
and unchecked
statements (The checked and unchecked statements).
下列作業會受到 checked
和運算子和語句所建立的溢位檢查內容影響 unchecked
:The following operations are affected by the overflow checking context established by the checked
and unchecked
operators and statements:
++
--
當運算元為整數類資料類型時,預先定義和一元運算子 (後置遞增和遞減運算子,以及前置遞增和遞減運算子) 。The predefined++
and--
unary operators (Postfix increment and decrement operators and Prefix increment and decrement operators), when the operand is of an integral type.-
當運算元為整數類資料類型時,預先定義的一元運算子 (一元減號運算子) 。The predefined-
unary operator (Unary minus operator), when the operand is of an integral type.+
-
*
/
當兩個運算元都是整數類資料類型時,預先定義的、、和二元運算子 (算術運算子) 。The predefined+
,-
,*
, and/
binary operators (Arithmetic operators), when both operands are of integral types.- 明確數值轉換 (明確數值轉換) 從一個整數類型到另一個整數類型,或從
float
或轉換double
成整數類資料類型。Explicit numeric conversions (Explicit numeric conversions) from one integral type to another integral type, or fromfloat
ordouble
to an integral type.
當上述其中一個作業產生的結果太大而無法在目的地類型中表示時,執行作業的內容會控制產生的行為:When one of the above operations produce a result that is too large to represent in the destination type, the context in which the operation is performed controls the resulting behavior:
- 在
checked
內容中,如果作業是常數運算式 (常數 運算式) ,就會發生編譯時期錯誤。In achecked
context, if the operation is a constant expression (Constant expressions), a compile-time error occurs. 否則,當作業在執行時間執行時,System.OverflowException
就會擲回。Otherwise, when the operation is performed at run-time, aSystem.OverflowException
is thrown. - 在
unchecked
內容中,會捨棄不符合目的地類型的任何高序位位,藉以截斷結果。In anunchecked
context, the result is truncated by discarding any high-order bits that do not fit in the destination type.
對於非常數運算式 (在執行時間) 評估且未以任何 checked
或運算子或語句括住的運算式 unchecked
, unchecked
除非外部因素 (例如編譯器參數和執行環境設定) 呼叫進行評估,否則會使用預設溢位檢查內容 checked
。For non-constant expressions (expressions that are evaluated at run-time) that are not enclosed by any checked
or unchecked
operators or statements, the default overflow checking context is unchecked
unless external factors (such as compiler switches and execution environment configuration) call for checked
evaluation.
針對常數運算式 (可在編譯時期) 完整評估的運算式,預設溢位檢查內容一律為 checked
。For constant expressions (expressions that can be fully evaluated at compile-time), the default overflow checking context is always checked
. 除非在內容中明確放置常數運算式,否則在 unchecked
運算式編譯時間評估期間發生的溢位一律會造成編譯時期錯誤。Unless a constant expression is explicitly placed in an unchecked
context, overflows that occur during the compile-time evaluation of the expression always cause compile-time errors.
匿名函式的主體不會受到匿名函 checked
式 unchecked
發生的或內容影響。The body of an anonymous function is not affected by checked
or unchecked
contexts in which the anonymous function occurs.
在範例中In the example
class Test
{
static readonly int x = 1000000;
static readonly int y = 1000000;
static int F() {
return checked(x * y); // Throws OverflowException
}
static int G() {
return unchecked(x * y); // Returns -727379968
}
static int H() {
return x * y; // Depends on default
}
}
因為兩個運算式都無法在編譯時間進行評估,所以不會回報任何編譯時期錯誤。no compile-time errors are reported since neither of the expressions can be evaluated at compile-time. 在執行時間,方法會擲回 F
System.OverflowException
,而方法會傳回 G
-727379968 (超出範圍結果) 的較低32位。At run-time, the F
method throws a System.OverflowException
, and the G
method returns -727379968 (the lower 32 bits of the out-of-range result). 方法的行為 H
取決於編譯的預設溢位檢查內容,但它與相同 F
或相同 G
。The behavior of the H
method depends on the default overflow checking context for the compilation, but it is either the same as F
or the same as G
.
在範例中In the example
class Test
{
const int x = 1000000;
const int y = 1000000;
static int F() {
return checked(x * y); // Compile error, overflow
}
static int G() {
return unchecked(x * y); // Returns -727379968
}
static int H() {
return x * y; // Compile error, overflow
}
}
在中評估常數運算式時所發生的溢 F
H
位,會導致報告編譯時期錯誤,因為運算式是在內容中進行評估 checked
。the overflows that occur when evaluating the constant expressions in F
and H
cause compile-time errors to be reported because the expressions are evaluated in a checked
context. 在中評估常數運算式時也會發生溢 G
位,但由於評估是在內容中發生 unchecked
,因此不會報告溢位。An overflow also occurs when evaluating the constant expression in G
, but since the evaluation takes place in an unchecked
context, the overflow is not reported.
checked
和 unchecked
運算子只會對包含在 " (
" 和 "" 標記內以程式集中的作業,影響溢位檢查內容 )
。The checked
and unchecked
operators only affect the overflow checking context for those operations that are textually contained within the "(
" and ")
" tokens. 運算子不會影響在評估包含的運算式時所叫用的函數成員。The operators have no effect on function members that are invoked as a result of evaluating the contained expression. 在範例中In the example
class Test
{
static int Multiply(int x, int y) {
return x * y;
}
static int F() {
return checked(Multiply(1000000, 1000000));
}
}
checked
在中使用 F
並不會影響中的評估 x * y
Multiply
,因此 x * y
會在預設溢位檢查內容中進行評估。the use of checked
in F
does not affect the evaluation of x * y
in Multiply
, so x * y
is evaluated in the default overflow checking context.
unchecked
在十六進位標記法中撰寫帶正負號整數類資料類型的常數時,運算子會很方便。The unchecked
operator is convenient when writing constants of the signed integral types in hexadecimal notation. 例如:For example:
class Test
{
public const int AllBits = unchecked((int)0xFFFFFFFF);
public const int HighBit = unchecked((int)0x80000000);
}
上述的兩個十六進位常數都屬於型別 uint
。Both of the hexadecimal constants above are of type uint
. 因為常數是在 int
不含運算子的範圍之外,所以 unchecked
轉換成 int
會產生編譯時期錯誤。Because the constants are outside the int
range, without the unchecked
operator, the casts to int
would produce compile-time errors.
checked
和 unchecked
運算子和語句可讓程式設計人員控制一些數值計算的特定層面。The checked
and unchecked
operators and statements allow programmers to control certain aspects of some numeric calculations. 不過,某些數值運算子的行為取決於其運算元的資料類型。However, the behavior of some numeric operators depends on their operands' data types. 例如,即使在明確的結構內,兩個小數位數一律會導致溢位例外狀況 unchecked
。For example, multiplying two decimals always results in an exception on overflow even within an explicitly unchecked
construct. 同樣地,即使在明確的結構內,將兩個浮點數相乘也不會造成溢位例外狀況 checked
。Similarly, multiplying two floats never results in an exception on overflow even within an explicitly checked
construct. 此外,其他運算子永遠不會受到檢查模式的影響,不論是預設或明確。In addition, other operators are never affected by the mode of checking, whether default or explicit.
預設值運算式Default value expressions
預設值運算式可用來取得預設值 (預設 值) 類型。A default value expression is used to obtain the default value (Default values) of a type. 通常會使用預設值運算式作為型別參數,因為如果型別參數是實值型別或參考型別,則可能不知道。Typically a default value expression is used for type parameters, since it may not be known if the type parameter is a value type or a reference type. (不會將常值轉換 null
為類型參數,除非已知類型參數是參考型別。 ) (No conversion exists from the null
literal to a type parameter unless the type parameter is known to be a reference type.)
default_value_expression
: 'default' '(' type ')'
;
如果 default_value_expression 中的 型 別在執行時間評估為參考型別,則結果會 null
轉換為該型別。If the type in a default_value_expression evaluates at run-time to a reference type, the result is null
converted to that type. 如果 default_value_expression 中的 型 別在執行時間評估為實值型別,則結果會是 Value_type 的預設值 (預設的函數) 。If the type in a default_value_expression evaluates at run-time to a value type, the result is the value_type's default value (Default constructors).
如果型別是參考型別,或是已知為參考型別 (型別參數條件約束) 的型別參數,則 default_value_expression 是常數運算式 (常數運算式) 。A default_value_expression is a constant expression (Constant expressions) if the type is a reference type or a type parameter that is known to be a reference type (Type parameter constraints). 此外,如果類型是下列其中一個數值型別,則 default_value_expression 是常數運算式: sbyte
、、、、、、、、、、、、 byte
short
ushort
int
uint
long
ulong
char
float
double
decimal
bool
或任何列舉型別。In addition, a default_value_expression is a constant expression if the type is one of the following value types: sbyte
, byte
, short
, ushort
, int
, uint
, long
, ulong
, char
, float
, double
, decimal
, bool
, or any enumeration type.
Nameof 運算式Nameof expressions
Nameof_expression 用來取得程式實體的名稱,做為常數位串。A nameof_expression is used to obtain the name of a program entity as a constant string.
nameof_expression
: 'nameof' '(' named_entity ')'
;
named_entity
: simple_name
| named_entity_target '.' identifier type_argument_list?
;
named_entity_target
: 'this'
| 'base'
| named_entity
| predefined_type
| qualified_alias_member
;
文法說, named_entity 運算元一律為運算式。Grammatically speaking, the named_entity operand is always an expression. 因為不是 nameof
保留的關鍵字,所以 nameof 運算式在語法上與簡單名稱的調用一律是不明確的 nameof
。Because nameof
is not a reserved keyword, a nameof expression is always syntactically ambiguous with an invocation of the simple name nameof
. 基於相容性的理由,如果名稱查閱 (簡單名稱) 名稱 nameof
成功,則會將運算式視為 invocation_expression --不論調用是否合法。For compatibility reasons, if a name lookup (Simple names) of the name nameof
succeeds, the expression is treated as an invocation_expression -- regardless of whether the invocation is legal. 否則就是 nameof_expression。Otherwise it is a nameof_expression.
Nameof_expression 的 named_entity 意義就是運算式的意義;也就是 simple_name、 base_access 或 member_access。The meaning of the named_entity of a nameof_expression is the meaning of it as an expression; that is, either as a simple_name, a base_access or a member_access. 不過,在 簡單名稱 和 成員存取 中描述的查閱會導致錯誤,因為在靜態內容中找到實例成員,所以 nameof_expression 不會產生這類錯誤。However, where the lookup described in Simple names and Member access results in an error because an instance member was found in a static context, a nameof_expression produces no such error.
這是一個編譯時期錯誤, named_entity 將方法群組指定為具有 type_argument_list。It is a compile-time error for a named_entity designating a method group to have a type_argument_list. 這是 named_entity_target 具有類型的編譯時期錯誤 dynamic
。It is a compile time error for a named_entity_target to have the type dynamic
.
Nameof_expression 是類型的常數運算式 string
,在執行時間不會有任何作用。A nameof_expression is a constant expression of type string
, and has no effect at runtime. 具體來說,它的 named_entity 不會進行評估,而且會基於明確指派分析的用途而忽略 () 簡單運算式的一般規則 。Specifically, its named_entity is not evaluated, and is ignored for the purposes of definite assignment analysis (General rules for simple expressions). 它的值是選擇性最終 type_argument_list 之前 named_entity 的最後一個識別碼,轉換方式如下:Its value is the last identifier of the named_entity before the optional final type_argument_list, transformed in the following way:
- 移除前置詞 "
@
" (如果使用的話)。The prefix "@
", if used, is removed. - 每個 unicode_escape_sequence 都會轉換成其對應的 unicode 字元。Each unicode_escape_sequence is transformed into its corresponding Unicode character.
- 移除任何 formatting_characters 。Any formatting_characters are removed.
這些是在測試識別碼是否相等時,在 識別碼 中套用的相同轉換。These are the same transformations applied in Identifiers when testing equality between identifiers.
TODO:範例TODO: examples
匿名方法運算式Anonymous method expressions
Anonymous_method_expression 是定義匿名函式的兩種方式之一。An anonymous_method_expression is one of two ways of defining an anonymous function. 這些會在匿名函式 運算式中進一步說明。These are further described in Anonymous function expressions.
一元運算子Unary operators
、、、、、、 ?
+
-
!
~
++
--
、Cast 和 await
運算子稱為一元運算子。The ?
, +
, -
, !
, ~
, ++
, --
, cast, and await
operators are called the unary operators.
unary_expression
: primary_expression
| null_conditional_expression
| '+' unary_expression
| '-' unary_expression
| '!' unary_expression
| '~' unary_expression
| pre_increment_expression
| pre_decrement_expression
| cast_expression
| await_expression
| unary_expression_unsafe
;
如果 unary_expression 的運算元具有編譯時間型別 dynamic
,則會動態繫結 (動態繫結) 。If the operand of a unary_expression has the compile-time type dynamic
, it is dynamically bound (Dynamic binding). 在此情況下, unary_expression 的編譯時間型別為 dynamic
,而且以下所述的解析將會在執行時間使用運算元的執行時間類型進行。In this case the compile-time type of the unary_expression is dynamic
, and the resolution described below will take place at run-time using the run-time type of the operand.
Null 條件運算子Null-conditional operator
Null 條件運算子只會在運算元為非 null 時,才會將作業清單套用至其運算元。The null-conditional operator applies a list of operations to its operand only if that operand is non-null. 否則,套用運算子的結果為 null
。Otherwise the result of applying the operator is null
.
null_conditional_expression
: primary_expression null_conditional_operations
;
null_conditional_operations
: null_conditional_operations? '?' '.' identifier type_argument_list?
| null_conditional_operations? '?' '[' argument_list ']'
| null_conditional_operations '.' identifier type_argument_list?
| null_conditional_operations '[' argument_list ']'
| null_conditional_operations '(' argument_list? ')'
;
作業清單可以包含成員存取和專案存取作業 (這些作業本身可以是 null 條件式) 和調用。The list of operations can include member access and element access operations (which may themselves be null-conditional), as well as invocation.
例如,運算式 a.b?[0]?.c()
是具有 primary_expression 的 null_conditional_expression a.b
, null_conditional_operations ?[0]
(null 條件式元素存取) , ?.c
(null 條件式成員存取) 和 ()
(調用) 。For example, the expression a.b?[0]?.c()
is a null_conditional_expression with a primary_expression a.b
and null_conditional_operations ?[0]
(null-conditional element access), ?.c
(null-conditional member access) and ()
(invocation).
對於 E
具有 primary_expression 的 null_conditional_expression P
,讓我們使用以 E0
程式方式取得的運算式, ?
從每一個有一個的 null_conditional_operations 中移除前置的運算式 E
。For a null_conditional_expression E
with a primary_expression P
, let E0
be the expression obtained by textually removing the leading ?
from each of the null_conditional_operations of E
that have one. 在概念上, E0
如果不是由所表示的任何 null 檢查都找不到,就會評估運算式 ?
null
。Conceptually, E0
is the expression that will be evaluated if none of the null checks represented by the ?
s do find a null
.
此外,讓我們 E1
以程式方式取得運算式, ?
從的第一個 null_conditional_operations 中移除前置 E
。Also, let E1
be the expression obtained by textually removing the leading ?
from just the first of the null_conditional_operations in E
. 如果只有一個) 或另一個 null_conditional_expression,這可能會導致 主要運算式 (?
。 This may lead to a primary-expression (if there was just one ?
) or to another null_conditional_expression.
例如,如果 E
是運算式,則 a.b?[0]?.c()
為運算式, E0
a.b[0].c()
而 E1
是運算式 a.b[0]?.c()
。For example, if E
is the expression a.b?[0]?.c()
, then E0
is the expression a.b[0].c()
and E1
is the expression a.b[0]?.c()
.
如果 E0
分類為 nothing,則 E
會分類為 nothing。If E0
is classified as nothing, then E
is classified as nothing. 否則會將 E 分類為值。Otherwise E is classified as a value.
E0
和 E1
可用來判斷的意義 E
:E0
and E1
are used to determine the meaning of E
:
如果
E
發生做為 statement_expression 的意義E
就與語句相同IfE
occurs as a statement_expression the meaning ofE
is the same as the statementif ((object)P != null) E1;
但只會評估 P 一次。except that P is evaluated only once.
否則,如果
E0
分類為任何未發生的編譯時期錯誤,則為。Otherwise, ifE0
is classified as nothing a compile-time error occurs.否則,請讓
T0
成為的型別E0
。Otherwise, letT0
be the type ofE0
.如果
T0
是不知道為參考型別或不可為 null 實值型別的型別參數,則會發生編譯時期錯誤。IfT0
is a type parameter that is not known to be a reference type or a non-nullable value type, a compile-time error occurs.如果
T0
是不可為 null 的實值型別,則的型別E
為T0?
,且的意義E
與IfT0
is a non-nullable value type, then the type ofE
isT0?
, and the meaning ofE
is the same as((object)P == null) ? (T0?)null : E1
但
P
只會評估一次。except thatP
is evaluated only once.否則,E 的類型為 T0,而 E 的意義與Otherwise the type of E is T0, and the meaning of E is the same as
((object)P == null) ? null : E1
但
P
只會評估一次。except thatP
is evaluated only once.
如果 E1
本身為 null_conditional_expression,則會再次套用這些規則,然後將測試嵌套, null
直到沒有進一步 ?
的,且運算式已減少到主要運算式為止 E0
。If E1
is itself a null_conditional_expression, then these rules are applied again, nesting the tests for null
until there are no further ?
's, and the expression has been reduced all the way down to the primary-expression E0
.
例如,如果運算式以 a.b?[0]?.c()
語句運算式的形式出現,就像在語句中一樣:For example, if the expression a.b?[0]?.c()
occurs as a statement-expression, as in the statement:
a.b?[0]?.c();
其意義相當於:its meaning is equivalent to:
if (a.b != null) a.b[0]?.c();
這同樣等同于:which again is equivalent to:
if (a.b != null) if (a.b[0] != null) a.b[0].c();
唯一的 a.b
例外 a.b[0]
是,而且只會評估一次。Except that a.b
and a.b[0]
are evaluated only once.
如果發生在使用其值的內容中,如下所示:If it occurs in a context where its value is used, as in:
var x = a.b?[0]?.c();
而且假設最後一個調用的型別不是不可為 null 的實值型別,其意義就相當於:and assuming that the type of the final invocation is not a non-nullable value type, its meaning is equivalent to:
var x = (a.b == null) ? null : (a.b[0] == null) ? null : a.b[0].c();
唯一的 a.b
例外 a.b[0]
是,而且只會評估一次。except that a.b
and a.b[0]
are evaluated only once.
Null 條件運算式作為投影初始化運算式Null-conditional expressions as projection initializers
Null 條件運算式只允許做為 anonymous_object_creation_expression (匿名物件建立運算式的 member_declarator ,) 如果它的結尾是 (選擇性的 null 條件式) 成員存取。A null-conditional expression is only allowed as a member_declarator in an anonymous_object_creation_expression (Anonymous object creation expressions) if it ends with an (optionally null-conditional) member access. 文法,此需求可表示為:Grammatically, this requirement can be expressed as:
null_conditional_member_access
: primary_expression null_conditional_operations? '?' '.' identifier type_argument_list?
| primary_expression null_conditional_operations '.' identifier type_argument_list?
;
這是上述 null_conditional_expression 文法的特殊案例。This is a special case of the grammar for null_conditional_expression above. Member_declarator 在 匿名物件建立運算式中的生產環境只包含 null_conditional_member_access。The production for member_declarator in Anonymous object creation expressions then includes only null_conditional_member_access.
Null 條件運算式作為語句運算式Null-conditional expressions as statement expressions
Null 條件運算式只允許做為 statement_expression 的 (運算式語句) 如果其結尾是調用。A null-conditional expression is only allowed as a statement_expression (Expression statements) if it ends with an invocation. 文法,此需求可表示為:Grammatically, this requirement can be expressed as:
null_conditional_invocation_expression
: primary_expression null_conditional_operations '(' argument_list? ')'
;
這是上述 null_conditional_expression 文法的特殊案例。This is a special case of the grammar for null_conditional_expression above. 運算式語句中 statement_expression 的生產環境只包含 null_conditional_invocation_expression。The production for statement_expression in Expression statements then includes only null_conditional_invocation_expression.
一元加號運算子Unary plus operator
若為表單的作業 +x
,則會套用一元運算子多載解析 (一元運算子 多載解析) 套用至選取特定的運算子執行。For an operation of the form +x
, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. 運算元會轉換成所選運算子的參數類型,而結果的型別則是運算子的傳回型別。The operand is converted to the parameter type of the selected operator, and the type of the result is the return type of the operator. 預先定義的一元加法運算子如下:The predefined unary plus operators are:
int operator +(int x);
uint operator +(uint x);
long operator +(long x);
ulong operator +(ulong x);
float operator +(float x);
double operator +(double x);
decimal operator +(decimal x);
針對上述每個運算子,結果只是運算元的值。For each of these operators, the result is simply the value of the operand.
一元減號運算子Unary minus operator
若為表單的作業 -x
,則會套用一元運算子多載解析 (一元運算子 多載解析) 套用至選取特定的運算子執行。For an operation of the form -x
, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. 運算元會轉換成所選運算子的參數類型,而結果的型別則是運算子的傳回型別。The operand is converted to the parameter type of the selected operator, and the type of the result is the return type of the operator. 預先定義的負運算子如下:The predefined negation operators are:
整數否定:Integer negation:
int operator -(int x); long operator -(long x);
結果的計算方式是
x
從零減去。The result is computed by subtractingx
from zero. 如果的值x
是運算元類型的最小可表示值 (-2 ^ 31 代表int
或-2 ^ 63 表示long
) ,則在x
運算元類型內無法表示的數學否定。If the value ofx
is the smallest representable value of the operand type (-2^31 forint
or -2^63 forlong
), then the mathematical negation ofx
is not representable within the operand type. 如果發生這種情況checked
,就會擲回,System.OverflowException
如果它發生在unchecked
內容中,結果就是運算元的值,而且不會報告溢位。If this occurs within achecked
context, aSystem.OverflowException
is thrown; if it occurs within anunchecked
context, the result is the value of the operand and the overflow is not reported.如果負運算子的運算元是型別,則
uint
會轉換成類型long
,而結果的型別為long
。If the operand of the negation operator is of typeuint
, it is converted to typelong
, and the type of the result islong
. 例外狀況是允許將int
值-2147483648 (-2 ^ 31) 撰寫為) 整數常 值的十進位 (整數常值的規則。An exception is the rule that permits theint
value -2147483648 (-2^31) to be written as a decimal integer literal (Integer literals).如果負運算子的運算元是型別
ulong
,就會發生編譯階段錯誤。If the operand of the negation operator is of typeulong
, a compile-time error occurs. 例外狀況是允許將long
值-9223372036854775808 (-2 ^ 63) 撰寫為) 整數常 值的十進位整數 (常值的規則。An exception is the rule that permits thelong
value -9223372036854775808 (-2^63) to be written as a decimal integer literal (Integer literals).浮點數否定:Floating-point negation:
float operator -(float x); double operator -(double x);
結果會是
x
其正負號反轉的值。The result is the value ofx
with its sign inverted. 如果x
是 nan,則結果也是 nan。Ifx
is NaN, the result is also NaN.小數否定:Decimal negation:
decimal operator -(decimal x);
結果的計算方式是
x
從零減去。The result is computed by subtractingx
from zero. Decimal 負號相當於使用類型的一元減號運算子System.Decimal
。Decimal negation is equivalent to using the unary minus operator of typeSystem.Decimal
.
邏輯否定運算子Logical negation operator
若為表單的作業 !x
,則會套用一元運算子多載解析 (一元運算子 多載解析) 套用至選取特定的運算子執行。For an operation of the form !x
, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. 運算元會轉換成所選運算子的參數類型,而結果的型別則是運算子的傳回型別。The operand is converted to the parameter type of the selected operator, and the type of the result is the return type of the operator. 只有一個預先定義的邏輯負運算子存在:Only one predefined logical negation operator exists:
bool operator !(bool x);
這個運算子會計算運算元的邏輯否定:如果運算元為 true
,則結果為 false
。This operator computes the logical negation of the operand: If the operand is true
, the result is false
. 如果運算元為 false
,則結果為 true
。If the operand is false
, the result is true
.
位元補充運算子 Bitwise complement operator
若為表單的作業 ~x
,則會套用一元運算子多載解析 (一元運算子 多載解析) 套用至選取特定的運算子執行。For an operation of the form ~x
, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. 運算元會轉換成所選運算子的參數類型,而結果的型別則是運算子的傳回型別。The operand is converted to the parameter type of the selected operator, and the type of the result is the return type of the operator. 預先定義的位補數運算子為:The predefined bitwise complement operators are:
int operator ~(int x);
uint operator ~(uint x);
long operator ~(long x);
ulong operator ~(ulong x);
針對上述每個運算子,作業的結果為的位補數 x
。For each of these operators, the result of the operation is the bitwise complement of x
.
每個列舉類型都會 E
隱含地提供下列位補數運算子:Every enumeration type E
implicitly provides the following bitwise complement operator:
E operator ~(E x);
評估的結果 ~x
(其中 x
是具有基礎類型的列舉型別運算式 E
)與 U
評估完全相同, (E)(~(U)x)
不同之處在于的轉換 E
一律會如同在 unchecked
(checked 和 unchecked 運算子) 的內容中一樣地執行。The result of evaluating ~x
, where x
is an expression of an enumeration type E
with an underlying type U
, is exactly the same as evaluating (E)(~(U)x)
, except that the conversion to E
is always performed as if in an unchecked
context (The checked and unchecked operators).
前置遞增和遞減運算子Prefix increment and decrement operators
pre_increment_expression
: '++' unary_expression
;
pre_decrement_expression
: '--' unary_expression
;
前置遞增或遞減運算的運算元必須是分類為變數、屬性存取或索引子存取的運算式。The operand of a prefix increment or decrement operation must be an expression classified as a variable, a property access, or an indexer access. 運算的結果是與運算元相同類型的值。The result of the operation is a value of the same type as the operand.
如果前置遞增或遞減運算的運算元是屬性或索引子存取,則屬性或索引子必須同時具有 get
和 set
存取子。If the operand of a prefix increment or decrement operation is a property or indexer access, the property or indexer must have both a get
and a set
accessor. 如果不是這種情況,就會發生系結階段錯誤。If this is not the case, a binding-time error occurs.
一元運算子多載解析 (一元運算子 多載解析) 適用于選取特定的運算子執行。Unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. 預先 ++
定義 --
的和運算子存在於下列類型:、、、、、、、、、、、 sbyte
byte
short
ushort
int
uint
long
ulong
char
float
double
decimal
和任何列舉類型。Predefined ++
and --
operators exist for the following types: sbyte
, byte
, short
, ushort
, int
, uint
, long
, ulong
, char
, float
, double
, decimal
, and any enum type. 預先定義的運算子會傳回將 ++
1 加入運算元所產生的值,而預先定義的運算子會傳回 --
從運算元減去1所產生的值。The predefined ++
operators return the value produced by adding 1 to the operand, and the predefined --
operators return the value produced by subtracting 1 from the operand. 在 checked
內容中,如果這個加法或減法的結果超出結果型別的範圍,且結果型別是整數型別或列舉型別, System.OverflowException
就會擲回。In a checked
context, if the result of this addition or subtraction is outside the range of the result type and the result type is an integral type or enum type, a System.OverflowException
is thrown.
表單的前置遞增或遞減作業的執行時間處理, ++x
或是 --x
由下列步驟所組成:The run-time processing of a prefix increment or decrement operation of the form ++x
or --x
consists of the following steps:
- 如果
x
分類為變數:Ifx
is classified as a variable:x
會評估以產生變數。x
is evaluated to produce the variable.- 使用的值
x
做為其引數來叫用選取的運算子。The selected operator is invoked with the value ofx
as its argument. - 運算子所傳回的值會儲存在評估所指定的位置
x
。The value returned by the operator is stored in the location given by the evaluation ofx
. - 運算子傳回的值會成為作業的結果。The value returned by the operator becomes the result of the operation.
- 如果
x
分類為屬性或索引子存取:Ifx
is classified as a property or indexer access:- 如果不是) ,實例運算式 (
x
static
,且如果x
是與相關聯的索引子存取) ,則會評估引數 (清單x
,且結果會用於後續get
和set
存取子調用。The instance expression (ifx
is notstatic
) and the argument list (ifx
is an indexer access) associated withx
are evaluated, and the results are used in the subsequentget
andset
accessor invocations. - 叫用的
get
存取子x
。Theget
accessor ofx
is invoked. - 使用存取子所傳回的值
get
做為其引數,以叫用選取的運算子。The selected operator is invoked with the value returned by theget
accessor as its argument. - 的
set
存取子x
會以運算子傳回的值做為其引數來叫用value
。Theset
accessor ofx
is invoked with the value returned by the operator as itsvalue
argument. - 運算子傳回的值會成為作業的結果。The value returned by the operator becomes the result of the operation.
- 如果不是) ,實例運算式 (
++
和 --
運算子也支援後置標記法 (後置遞增和遞減運算子) 。The ++
and --
operators also support postfix notation (Postfix increment and decrement operators). 或的結果通常是在作業 x++
x--
之前的值 x
,而或的結果 ++x
是作業之後的 --x
值 x
。Typically, the result of x++
or x--
is the value of x
before the operation, whereas the result of ++x
or --x
is the value of x
after the operation. 在任一種情況下, x
其本身在作業之後都具有相同的值。In either case, x
itself has the same value after the operation.
您 operator++
operator--
可以使用後置或前置標記法來叫用或實作為。An operator++
or operator--
implementation can be invoked using either postfix or prefix notation. 這兩種標記法不能有個別的運算子實現。It is not possible to have separate operator implementations for the two notations.
轉換運算式Cast expressions
Cast_expression 用來明確地將運算式轉換成指定的型別。A cast_expression is used to explicitly convert an expression to a given type.
cast_expression
: '(' type ')' unary_expression
;
表單的 cast_expression (T)E
,其中 T
是 類型 ,而 E
是 unary_expression,會執行明確的轉換, (將值的 明確轉換) E
為類型 T
。A cast_expression of the form (T)E
, where T
is a type and E
is a unary_expression, performs an explicit conversion (Explicit conversions) of the value of E
to type T
. 如果沒有明確的轉換 E
,則 T
會發生系結階段錯誤。If no explicit conversion exists from E
to T
, a binding-time error occurs. 否則,結果會是明確轉換所產生的值。Otherwise, the result is the value produced by the explicit conversion. 結果一律會分類為值,即使代表變數也是一樣 E
。The result is always classified as a value, even if E
denotes a variable.
Cast_expression 的文法會導致特定的語法歧義。The grammar for a cast_expression leads to certain syntactic ambiguities. 例如,您 (x)-y
可以將運算式解釋為 cast_expression (將轉換為 -y
類型 x
) 或 additive_expression 與計算值的 parenthesized_expression (結合 x - y)
。For example, the expression (x)-y
could either be interpreted as a cast_expression (a cast of -y
to type x
) or as an additive_expression combined with a parenthesized_expression (which computes the value x - y)
.
若要解決 cast_expression 不明確的問題,請注意下列規則:只有在下列其中一個條件成立時,才會將一或多個 標記 () 空白字元 的序列,視為 cast_expression 的開頭:To resolve cast_expression ambiguities, the following rule exists: A sequence of one or more token s (White space) enclosed in parentheses is considered the start of a cast_expression only if at least one of the following are true:
- 標記的序列是 類型 的正確文法,但不是 運算式 的正確文法。The sequence of tokens is correct grammar for a type, but not for an expression.
- Token 的順序是正確的 型 別文法,而緊接在右括弧後面的 token 是 token "
~
"、token "!
"、token "(
"、 (Unicode 字元 escape 序列) 的 識別碼、常 值 (常值) 或任何 關鍵字 (關鍵字) 除了as
和之外is
。The sequence of tokens is correct grammar for a type, and the token immediately following the closing parentheses is the token "~
", the token "!
", the token "(
", an identifier (Unicode character escape sequences), a literal (Literals), or any keyword (Keywords) exceptas
andis
.
上述「正確的文法」一詞表示權杖的順序必須符合特定的文法生產。The term "correct grammar" above means only that the sequence of tokens must conform to the particular grammatical production. 明確地說,它並不會考慮任何組成識別碼的實際意義。It specifically does not consider the actual meaning of any constituent identifiers. 例如,如果 x
和 y
是識別碼,則 x.y
為類型的正確文法,即使 x.y
實際上未表示型別也是一樣。For example, if x
and y
are identifiers, then x.y
is correct grammar for a type, even if x.y
doesn't actually denote a type.
從去除混淆規則開始,如果 x
和 y
是識別碼、 (x)y
、和都 (x)(y)
(x)(-y)
是 cast_expression s,但卻 (x)-y
不是,即使 x
識別型別也是一樣。From the disambiguation rule it follows that, if x
and y
are identifiers, (x)y
, (x)(y)
, and (x)(-y)
are cast_expression s, but (x)-y
is not, even if x
identifies a type. 但是,如果 x
是識別預先定義之類型 (例如) 的關鍵字 int
,則這四種形式都會 cast_expression s (,因為這類關鍵字) 本身可能不是運算式。However, if x
is a keyword that identifies a predefined type (such as int
), then all four forms are cast_expression s (because such a keyword could not possibly be an expression by itself).
Await 運算式Await expressions
Await 運算子用來暫止封閉非同步函式的評估,直到運算元所表示的非同步作業完成為止。The await operator is used to suspend evaluation of the enclosing async function until the asynchronous operation represented by the operand has completed.
await_expression
: 'await' unary_expression
;
Await_expression 只能在非同步函式的主體中使用 (非同步函式) 。An await_expression is only allowed in the body of an async function (Async functions). 在最接近的封入非同步函式內, await_expression 可能不會出現在這些位置:Within the nearest enclosing async function, an await_expression may not occur in these places:
- 在嵌套 (非非同步) 匿名函式中Inside a nested (non-async) anonymous function
- 在 lock_statement 的區塊內Inside the block of a lock_statement
- 在 unsafe 內容中In an unsafe context
請注意, await_expression 不能出現在 query_expression 的大部分位置中,因為它們在語法上是轉換成使用非非同步 lambda 運算式。Note that an await_expression cannot occur in most places within a query_expression, because those are syntactically transformed to use non-async lambda expressions.
在非同步函式內, await
不能當做識別碼使用。Inside of an async function, await
cannot be used as an identifier. 因此,在 await 運算式和涉及識別碼的各種運算式之間,不會有語法上的混淆。There is therefore no syntactic ambiguity between await-expressions and various expressions involving identifiers. 在非同步函式之外,會 await
作為一般識別碼。Outside of async functions, await
acts as a normal identifier.
Await_expression 的運算元稱為 *task _。The operand of an await_expression is called the *task _. 它代表在評估 _await_expression * 時,可能或可能不會完成的非同步作業。It represents an asynchronous operation that may or may not be complete at the time the _await_expression* is evaluated. Await 運算子的目的是暫停執行封閉的非同步函式,直到等候的工作完成,然後取得其結果。The purpose of the await operator is to suspend execution of the enclosing async function until the awaited task is complete, and then obtain its outcome.
可等候運算式Awaitable expressions
需要 可等候 await 運算式的工作。The task of an await expression is required to be awaitable. t
如果下列其中一項成立,就會可等候運算式:An expression t
is awaitable if one of the following holds:
t
是編譯時間類型dynamic
t
is of compile time typedynamic
t
具有可存取的實例或GetAwaiter
使用不含參數的擴充方法,而且沒有任何型別參數,以及下列所有的傳回型A
別:t
has an accessible instance or extension method calledGetAwaiter
with no parameters and no type parameters, and a return typeA
for which all of the following hold:A``System.Runtime.CompilerServices.INotifyCompletion
為了簡潔起見,會實 (的介面INotifyCompletion
)A
implements the interfaceSystem.Runtime.CompilerServices.INotifyCompletion
(hereafter known asINotifyCompletion
for brevity)A
具有類型的可存取、可讀取的實例屬性IsCompleted``bool
A
has an accessible, readable instance propertyIsCompleted
of typebool
A
具有GetResult
無參數且沒有類型參數的可存取的實例方法A
has an accessible instance methodGetResult
with no parameters and no type parameters
方法的用途 GetAwaiter
是取得工作的 *awaiter _。The purpose of the GetAwaiter
method is to obtain an *awaiter _ for the task. 此類型 A
稱為 await 運算式的 _ *awaiter 類型**。The type A
is called the _ awaiter type* for the await expression.
屬性的目的 IsCompleted
是要判斷工作是否已完成。The purpose of the IsCompleted
property is to determine if the task is already complete. 若是如此,就不需要暫停評估。If so, there is no need to suspend evaluation.
方法的用途是將「 INotifyCompletion.OnCompleted
接續」註冊至工作,也就是 System.Action
在工作完成之後,將會叫用) 類型的委派 (。The purpose of the INotifyCompletion.OnCompleted
method is to sign up a "continuation" to the task; i.e. a delegate (of type System.Action
) that will be invoked once the task is complete.
方法的用途 GetResult
是在工作完成之後取得工作的結果。The purpose of the GetResult
method is to obtain the outcome of the task once it is complete. 這項結果可能會成功完成,可能是結果值,也可能是方法擲回的例外狀況 GetResult
。This outcome may be successful completion, possibly with a result value, or it may be an exception which is thrown by the GetResult
method.
Await 運算式的分類Classification of await expressions
運算式的 await t
分類方式與運算式相同 (t).GetAwaiter().GetResult()
。The expression await t
is classified the same way as the expression (t).GetAwaiter().GetResult()
. 因此,如果的傳回型 GetResult
別為 void
,則 await_expression 分類為 nothing。Thus, if the return type of GetResult
is void
, the await_expression is classified as nothing. 如果它有非 void 的傳回型別 T
,則會將 await_expression 分類為類型的值 T
。If it has a non-void return type T
, the await_expression is classified as a value of type T
.
Await 運算式的執行時間評估Runtime evaluation of await expressions
在執行時間,運算式的 await t
評估方式如下:At runtime, the expression await t
is evaluated as follows:
- 藉
a
由評估運算式來取得 awaiter(t).GetAwaiter()
。An awaitera
is obtained by evaluating the expression(t).GetAwaiter()
. - 藉
bool
b
由評估運算式來取得(a).IsCompleted
。Abool
b
is obtained by evaluating the expression(a).IsCompleted
. - 如果
b
為,false
則評估取決於是否a
執行介面 (接下來System.Runtime.CompilerServices.ICriticalNotifyCompletion
稱為ICriticalNotifyCompletion
以求簡潔) 。Ifb
isfalse
then evaluation depends on whethera
implements the interfaceSystem.Runtime.CompilerServices.ICriticalNotifyCompletion
(hereafter known asICriticalNotifyCompletion
for brevity). 這項檢查是在系結階段完成;也就是在執行時間a
中,如果有編譯時間類型,則為dynamic
,否則為。This check is done at binding time; i.e. at runtime ifa
has the compile time typedynamic
, and at compile time otherwise. 讓r
) 的 (非同步 函式表示繼續委派:Letr
denote the resumption delegate (Async functions):- 如果
a
未執行ICriticalNotifyCompletion
,則(a as (INotifyCompletion)).OnCompleted(r)
會評估運算式。Ifa
does not implementICriticalNotifyCompletion
, then the expression(a as (INotifyCompletion)).OnCompleted(r)
is evaluated. - 如果
a
確實執行ICriticalNotifyCompletion
,則(a as (ICriticalNotifyCompletion)).UnsafeOnCompleted(r)
會評估運算式。Ifa
does implementICriticalNotifyCompletion
, then the expression(a as (ICriticalNotifyCompletion)).UnsafeOnCompleted(r)
is evaluated. - 然後評估會暫停,控制權會傳回給 async 函式的目前呼叫者。Evaluation is then suspended, and control is returned to the current caller of the async function.
- 如果
- 在 (if) 之後
b
,或在稍後叫用繼續true
委派 (如果b
false
) ,則(a).GetResult()
會評估運算式。Either immediately after (ifb
wastrue
), or upon later invocation of the resumption delegate (ifb
wasfalse
), the expression(a).GetResult()
is evaluated. 如果它傳回值,該值就是 await_expression 的結果。If it returns a value, that value is the result of the await_expression. 否則結果為 nothing。Otherwise the result is nothing.
介面方法的 awaiter 執行 INotifyCompletion.OnCompleted
,而且 ICriticalNotifyCompletion.UnsafeOnCompleted
應該會造成 r
最多叫用委派一次。An awaiter's implementation of the interface methods INotifyCompletion.OnCompleted
and ICriticalNotifyCompletion.UnsafeOnCompleted
should cause the delegate r
to be invoked at most once. 否則,封閉式非同步函式的行為是未定義的。Otherwise, the behavior of the enclosing async function is undefined.
算術運算子Arithmetic operators
*
、、 /
%
、 +
和 -
運算子稱為算術運算子。The *
, /
, %
, +
, and -
operators are called the arithmetic operators.
multiplicative_expression
: unary_expression
| multiplicative_expression '*' unary_expression
| multiplicative_expression '/' unary_expression
| multiplicative_expression '%' unary_expression
;
additive_expression
: multiplicative_expression
| additive_expression '+' multiplicative_expression
| additive_expression '-' multiplicative_expression
;
如果算術運算子的運算元具有編譯時間型別 dynamic
,則運算式會動態繫結 (動態繫結) 。If an operand of an arithmetic operator has the compile-time type dynamic
, then the expression is dynamically bound (Dynamic binding). 在此情況下,運算式的編譯時間型別是 dynamic
,而且下面所述的解析將會在執行時間使用具有編譯時間類型之運算元的執行時間型別進行 dynamic
。In this case the compile-time type of the expression is dynamic
, and the resolution described below will take place at run-time using the run-time type of those operands that have the compile-time type dynamic
.
乘法運算子Multiplication operator
針對格式的作業 x * y
,二元運算子多載解析 (二元運算子 多載解析) 套用至選取特定的運算子執行。For an operation of the form x * y
, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. 運算元會轉換成所選運算子的參數類型,而結果的型別則是運算子的傳回型別。The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.
預先定義的乘法運算子如下所示。The predefined multiplication operators are listed below. 運算子會計算和的產品 x
y
。The operators all compute the product of x
and y
.
整數乘法:Integer multiplication:
int operator *(int x, int y); uint operator *(uint x, uint y); long operator *(long x, long y); ulong operator *(ulong x, ulong y);
在
checked
內容中,如果產品超出結果型別的範圍,System.OverflowException
就會擲回。In achecked
context, if the product is outside the range of the result type, aSystem.OverflowException
is thrown. 在unchecked
內容中,不會報告溢位,而且會捨棄結果型別範圍之外的任何大量高序位位。In anunchecked
context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.浮點數乘法:Floating-point multiplication:
float operator *(float x, float y); double operator *(double x, double y);
會根據 IEEE 754 算術的規則來計算產品。The product is computed according to the rules of IEEE 754 arithmetic. 下表列出非零有限值、零、無限大和 NaN 所有可能組合的結果。The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. 在下表中,
x
和y
是正有限值。In the table,x
andy
are positive finite values.z
是x * y
的結果。z
is the result ofx * y
. 如果結果對目的地類型而言太大,則z
為無限大。If the result is too large for the destination type,z
is infinity. 如果結果對目的地類型而言太小,則z
為零。If the result is too small for the destination type,z
is zero.+y+y -y-y +0+0 -0-0 +inf+inf -inf-inf NaNNaN +x+x +z+z -Z-z +0+0 -0-0 +inf+inf -inf-inf NaNNaN -X-x -Z-z +z+z -0-0 +0+0 -inf-inf +inf+inf NaNNaN +0+0 +0+0 -0-0 +0+0 -0-0 NaNNaN NaNNaN NaNNaN -0-0 -0-0 +0+0 -0-0 +0+0 NaNNaN NaNNaN NaNNaN +inf+inf +inf+inf -inf-inf NaNNaN NaNNaN +inf+inf -inf-inf NaNNaN -inf-inf -inf-inf +inf+inf NaNNaN NaNNaN -inf-inf +inf+inf NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN 十進位乘法:Decimal multiplication:
decimal operator *(decimal x, decimal y);
如果產生的值太大而無法以格式表示
decimal
,System.OverflowException
就會擲回。If the resulting value is too large to represent in thedecimal
format, aSystem.OverflowException
is thrown. 如果結果值太小而無法以decimal
格式表示,則結果為零。If the result value is too small to represent in thedecimal
format, the result is zero. 結果的小數位數是在任何四捨五入之前,這是兩個運算元之刻度的總和。The scale of the result, before any rounding, is the sum of the scales of the two operands.Decimal 乘法相當於使用類型的乘法運算子
System.Decimal
。Decimal multiplication is equivalent to using the multiplication operator of typeSystem.Decimal
.
除法運算子Division operator
針對格式的作業 x / y
,二元運算子多載解析 (二元運算子 多載解析) 套用至選取特定的運算子執行。For an operation of the form x / y
, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. 運算元會轉換成所選運算子的參數類型,而結果的型別則是運算子的傳回型別。The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.
下列是預先定義的除法運算子。The predefined division operators are listed below. 運算子會計算和的商 x
y
。The operators all compute the quotient of x
and y
.
整數除法:Integer division:
int operator /(int x, int y); uint operator /(uint x, uint y); long operator /(long x, long y); ulong operator /(ulong x, ulong y);
如果右運算元的值為零,
System.DivideByZeroException
則會擲回。If the value of the right operand is zero, aSystem.DivideByZeroException
is thrown.相除會將結果四捨五入至零。The division rounds the result towards zero. 因此,結果的絕對值會是小於或等於兩個運算元之商絕對值的最大可能整數。Thus the absolute value of the result is the largest possible integer that is less than or equal to the absolute value of the quotient of the two operands. 當兩個運算元的正負號相同時,如果兩個運算元具有相同的正負號,則結果為零或正數。The result is zero or positive when the two operands have the same sign and zero or negative when the two operands have opposite signs.
如果左運算元是最小的可
int
long
表示值或值,右邊的運算元為-1
,就會發生溢位。If the left operand is the smallest representableint
orlong
value and the right operand is-1
, an overflow occurs. 在checked
內容中,這會造成System.ArithmeticException
) 擲回 (或子類別。In achecked
context, this causes aSystem.ArithmeticException
(or a subclass thereof) to be thrown. 在unchecked
內容中,它會在執行時定義為是否擲System.ArithmeticException
回 (或子類別) ,或溢位未報告,且結果值為左運算元的值。In anunchecked
context, it is implementation-defined as to whether aSystem.ArithmeticException
(or a subclass thereof) is thrown or the overflow goes unreported with the resulting value being that of the left operand.浮點數除法:Floating-point division:
float operator /(float x, float y); double operator /(double x, double y);
商會根據 IEEE 754 算術的規則來計算。The quotient is computed according to the rules of IEEE 754 arithmetic. 下表列出非零有限值、零、無限大和 NaN 所有可能組合的結果。The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. 在下表中,
x
和y
是正有限值。In the table,x
andy
are positive finite values.z
是x / y
的結果。z
is the result ofx / y
. 如果結果對目的地類型而言太大,則z
為無限大。If the result is too large for the destination type,z
is infinity. 如果結果對目的地類型而言太小,則z
為零。If the result is too small for the destination type,z
is zero.+y+y -y-y +0+0 -0-0 +inf+inf -inf-inf NaNNaN +x+x +z+z -Z-z +inf+inf -inf-inf +0+0 -0-0 NaNNaN -X-x -Z-z +z+z -inf-inf +inf+inf -0-0 +0+0 NaNNaN +0+0 +0+0 -0-0 NaNNaN NaNNaN +0+0 -0-0 NaNNaN -0-0 -0-0 +0+0 NaNNaN NaNNaN -0-0 +0+0 NaNNaN +inf+inf +inf+inf -inf-inf +inf+inf -inf-inf NaNNaN NaNNaN NaNNaN -inf-inf -inf-inf +inf+inf -inf-inf +inf+inf NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN 小數除法:Decimal division:
decimal operator /(decimal x, decimal y);
如果右運算元的值為零,
System.DivideByZeroException
則會擲回。If the value of the right operand is zero, aSystem.DivideByZeroException
is thrown. 如果產生的值太大而無法以格式表示decimal
,System.OverflowException
就會擲回。If the resulting value is too large to represent in thedecimal
format, aSystem.OverflowException
is thrown. 如果結果值太小而無法以decimal
格式表示,則結果為零。If the result value is too small to represent in thedecimal
format, the result is zero. 結果的小數位數是將結果等於最接近的可表示十進位值的最小小數位數。The scale of the result is the smallest scale that will preserve a result equal to the nearest representable decimal value to the true mathematical result.小數除法相當於使用類型的除法運算子
System.Decimal
。Decimal division is equivalent to using the division operator of typeSystem.Decimal
.
餘數運算子Remainder operator
針對格式的作業 x % y
,二元運算子多載解析 (二元運算子 多載解析) 套用至選取特定的運算子執行。For an operation of the form x % y
, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. 運算元會轉換成所選運算子的參數類型,而結果的型別則是運算子的傳回型別。The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.
預先定義的餘數運算子如下所示。The predefined remainder operators are listed below. 運算子會計算和之間相除的餘數 x
y
。The operators all compute the remainder of the division between x
and y
.
整數餘數:Integer remainder:
int operator %(int x, int y); uint operator %(uint x, uint y); long operator %(long x, long y); ulong operator %(ulong x, ulong y);
的結果
x % y
是所產生的值x - (x / y) * y
。The result ofx % y
is the value produced byx - (x / y) * y
. 如果y
為零,System.DivideByZeroException
則會擲回。Ify
is zero, aSystem.DivideByZeroException
is thrown.如果左運算元是最小
int
值或long
值,右邊運算元是-1
,System.OverflowException
則會擲回。If the left operand is the smallestint
orlong
value and the right operand is-1
, aSystem.OverflowException
is thrown. 在沒有任何情況下x % y
,會擲回例外狀況,x / y
而不會擲回例外狀況。In no case doesx % y
throw an exception wherex / y
would not throw an exception.浮點數餘數:Floating-point remainder:
float operator %(float x, float y); double operator %(double x, double y);
下表列出非零有限值、零、無限大和 NaN 所有可能組合的結果。The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. 在下表中,
x
和y
是正有限值。In the table,x
andy
are positive finite values.z
是x % y
和計算的結果x - n * y
,其中n
是小於或等於的最大可能整數x / y
。z
is the result ofx % y
and is computed asx - n * y
, wheren
is the largest possible integer that is less than or equal tox / y
. 這種計算餘數的方法與用於整數運算元的方法類似,但不同于 IEEE 754 定義 (,n
也就是最接近) 的整數x / y
。This method of computing the remainder is analogous to that used for integer operands, but differs from the IEEE 754 definition (in whichn
is the integer closest tox / y
).+y+y -y-y +0+0 -0-0 +inf+inf -inf-inf NaNNaN +x+x +z+z +z+z NaNNaN NaNNaN xx xx NaNNaN -X-x -Z-z -Z-z NaNNaN NaNNaN -X-x -X-x NaNNaN +0+0 +0+0 +0+0 NaNNaN NaNNaN +0+0 +0+0 NaNNaN -0-0 -0-0 -0-0 NaNNaN NaNNaN -0-0 -0-0 NaNNaN +inf+inf NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN -inf-inf NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN 小數餘數:Decimal remainder:
decimal operator %(decimal x, decimal y);
如果右運算元的值為零,
System.DivideByZeroException
則會擲回。If the value of the right operand is zero, aSystem.DivideByZeroException
is thrown. 在任何四捨五入之前,結果的小數位數是兩個運算元的最大刻度,而結果的正負號(如果非零)則與相同x
。The scale of the result, before any rounding, is the larger of the scales of the two operands, and the sign of the result, if non-zero, is the same as that ofx
.小數餘數相當於使用類型的餘數運算子
System.Decimal
。Decimal remainder is equivalent to using the remainder operator of typeSystem.Decimal
.
加法運算子Addition operator
針對格式的作業 x + y
,二元運算子多載解析 (二元運算子 多載解析) 套用至選取特定的運算子執行。For an operation of the form x + y
, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. 運算元會轉換成所選運算子的參數類型,而結果的型別則是運算子的傳回型別。The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.
預先定義的加法運算子如下所示。The predefined addition operators are listed below. 針對數值和列舉類型,預先定義的加法運算子會計算兩個運算元的總和。For numeric and enumeration types, the predefined addition operators compute the sum of the two operands. 當一個或兩個運算元的類型為 string 時,預先定義的加法運算子會串連運算元的字串表示。When one or both operands are of type string, the predefined addition operators concatenate the string representation of the operands.
整數加法:Integer addition:
int operator +(int x, int y); uint operator +(uint x, uint y); long operator +(long x, long y); ulong operator +(ulong x, ulong y);
在
checked
內容中,如果總和超出結果型別的範圍,System.OverflowException
就會擲回。In achecked
context, if the sum is outside the range of the result type, aSystem.OverflowException
is thrown. 在unchecked
內容中,不會報告溢位,而且會捨棄結果型別範圍之外的任何大量高序位位。In anunchecked
context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.浮點數加法:Floating-point addition:
float operator +(float x, float y); double operator +(double x, double y);
總和是根據 IEEE 754 算術的規則來計算。The sum is computed according to the rules of IEEE 754 arithmetic. 下表列出非零有限值、零、無限大和 NaN 所有可能組合的結果。The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. 在下表中,
x
和y
是非零有限值,而z
是x + y
的結果。In the table,x
andy
are nonzero finite values, andz
is the result ofx + y
. 如果x
和y
具有相同的大小,但正負號相反,則z
為正零。Ifx
andy
have the same magnitude but opposite signs,z
is positive zero. 如果x + y
太大而無法在目的地類型中表示,z
則為具有相同正負號的無限大x + y
。Ifx + y
is too large to represent in the destination type,z
is an infinity with the same sign asx + y
.yy +0+0 -0-0 +inf+inf -inf-inf NaNNaN xx zz xx xx +inf+inf -inf-inf NaNNaN +0+0 yy +0+0 +0+0 +inf+inf -inf-inf NaNNaN -0-0 yy +0+0 -0-0 +inf+inf -inf-inf NaNNaN +inf+inf +inf+inf +inf+inf +inf+inf +inf+inf NaNNaN NaNNaN -inf-inf -inf-inf -inf-inf -inf-inf NaNNaN -inf-inf NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN Decimal 加法:Decimal addition:
decimal operator +(decimal x, decimal y);
如果產生的值太大而無法以格式表示
decimal
,System.OverflowException
就會擲回。If the resulting value is too large to represent in thedecimal
format, aSystem.OverflowException
is thrown. 在任何四捨五入之前,結果的小數位數是兩個運算元的尺規越大。The scale of the result, before any rounding, is the larger of the scales of the two operands.Decimal 加法相當於使用類型的加法運算子
System.Decimal
。Decimal addition is equivalent to using the addition operator of typeSystem.Decimal
.列舉加法。Enumeration addition. 每個列舉型別都會隱含地提供下列預先定義的運算子,其中
E
是列舉型別,而U
是的基礎型別E
:Every enumeration type implicitly provides the following predefined operators, whereE
is the enum type, andU
is the underlying type ofE
:E operator +(E x, U y); E operator +(U x, E y);
在執行時間,這些運算子的評估方式完全相同
(E)((U)x + (U)y)
。At run-time these operators are evaluated exactly as(E)((U)x + (U)y)
.字串串連:String concatenation:
string operator +(string x, string y); string operator +(string x, object y); string operator +(object x, string y);
二元運算子的這些多載會
+
執行字串串連。These overloads of the binary+
operator perform string concatenation. 如果字串串連的運算元是null
,則會取代空字串。If an operand of string concatenation isnull
, an empty string is substituted. 否則,任何非字串引數都會叫用繼承自類型的虛擬方法,以轉換成其字串表示ToString
object
。Otherwise, any non-string argument is converted to its string representation by invoking the virtualToString
method inherited from typeobject
. 如果ToString
傳回null
,則會取代空字串。IfToString
returnsnull
, an empty string is substituted.using System; class Test { static void Main() { string s = null; Console.WriteLine("s = >" + s + "<"); // displays s = >< int i = 1; Console.WriteLine("i = " + i); // displays i = 1 float f = 1.2300E+15F; Console.WriteLine("f = " + f); // displays f = 1.23E+15 decimal d = 2.900m; Console.WriteLine("d = " + d); // displays d = 2.900 } }
字串串連運算子的結果是一個字串,其中包含左運算元的字元以及右運算元的字元。 字串串連運算子永遠不會傳回
null
值。System.OutOfMemoryException
如果沒有足夠的記憶體可配置結果字串,可能會擲回。ASystem.OutOfMemoryException
may be thrown if there is not enough memory available to allocate the resulting string.委派組合。Delegate combination. 每個委派型別都會隱含地提供下列預先定義的運算子,其中
D
是委派型別:Every delegate type implicitly provides the following predefined operator, whereD
is the delegate type:D operator +(D x, D y);
二元
+
運算子會在兩個運算元都屬於某個委派型別時,執行委派組合D
。The binary+
operator performs delegate combination when both operands are of some delegate typeD
. (如果運算元有不同的委派類型,就會發生系結時期錯誤。 ) 如果第一個運算元是,則作業的null
結果會是第二個運算元的值 (即使也null
) 。(If the operands have different delegate types, a binding-time error occurs.) If the first operand isnull
, the result of the operation is the value of the second operand (even if that is alsonull
). 否則,如果第二個運算元是null
,則運算的結果會是第一個運算元的值。Otherwise, if the second operand isnull
, then the result of the operation is the value of the first operand. 否則,作業的結果會是新的委派實例,當叫用它時,會叫用第一個運算元,然後叫用第二個運算元。Otherwise, the result of the operation is a new delegate instance that, when invoked, invokes the first operand and then invokes the second operand. 如需委派組合的範例,請參閱 減法運算子 和 委派調用。For examples of delegate combination, see Subtraction operator and Delegate invocation. 由於不是System.Delegate
委派型別,operator
+
因此不會為它定義。SinceSystem.Delegate
is not a delegate type,operator
+
is not defined for it.
減法運算子Subtraction operator
針對格式的作業 x - y
,二元運算子多載解析 (二元運算子 多載解析) 套用至選取特定的運算子執行。For an operation of the form x - y
, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. 運算元會轉換成所選運算子的參數類型,而結果的型別則是運算子的傳回型別。The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.
預先定義的減法運算子如下所示。The predefined subtraction operators are listed below. 所有運算子都會減去 y
x
。The operators all subtract y
from x
.
整數減法:Integer subtraction:
int operator -(int x, int y); uint operator -(uint x, uint y); long operator -(long x, long y); ulong operator -(ulong x, ulong y);
在
checked
內容中,如果差異超出結果型別的範圍,System.OverflowException
就會擲回。In achecked
context, if the difference is outside the range of the result type, aSystem.OverflowException
is thrown. 在unchecked
內容中,不會報告溢位,而且會捨棄結果型別範圍之外的任何大量高序位位。In anunchecked
context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.浮點數減法:Floating-point subtraction:
float operator -(float x, float y); double operator -(double x, double y);
差異是根據 IEEE 754 算術的規則來計算。The difference is computed according to the rules of IEEE 754 arithmetic. 下表列出所有可能的非零有限值、零、無限大和 Nan 組合的結果。The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaNs. 在下表中,
x
和y
是非零有限值,而z
是x - y
的結果。In the table,x
andy
are nonzero finite values, andz
is the result ofx - y
. 如果x
和y
相等,則z
為正零。Ifx
andy
are equal,z
is positive zero. 如果x - y
太大而無法在目的地類型中表示,z
則為具有相同正負號的無限大x - y
。Ifx - y
is too large to represent in the destination type,z
is an infinity with the same sign asx - y
.yy +0+0 -0-0 +inf+inf -inf-inf NaNNaN xx zz xx xx -inf-inf +inf+inf NaNNaN +0+0 -y-y +0+0 +0+0 -inf-inf +inf+inf NaNNaN -0-0 -y-y -0-0 +0+0 -inf-inf +inf+inf NaNNaN +inf+inf +inf+inf +inf+inf +inf+inf NaNNaN +inf+inf NaNNaN -inf-inf -inf-inf -inf-inf -inf-inf -inf-inf NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN NaNNaN 十進位減法:Decimal subtraction:
decimal operator -(decimal x, decimal y);
如果產生的值太大而無法以格式表示
decimal
,System.OverflowException
就會擲回。If the resulting value is too large to represent in thedecimal
format, aSystem.OverflowException
is thrown. 在任何四捨五入之前,結果的小數位數是兩個運算元的尺規越大。The scale of the result, before any rounding, is the larger of the scales of the two operands.Decimal 減法相當於使用類型的減法運算子
System.Decimal
。Decimal subtraction is equivalent to using the subtraction operator of typeSystem.Decimal
.列舉減法。Enumeration subtraction. 每個列舉型別都會隱含地提供下列預先定義的運算子,其中
E
是列舉型別,而U
是的基礎型別E
:Every enumeration type implicitly provides the following predefined operator, whereE
is the enum type, andU
is the underlying type ofE
:U operator -(E x, E y);
這個運算子的評估方式完全相同
(U)((U)x - (U)y)
。This operator is evaluated exactly as(U)((U)x - (U)y)
. 換句話說,運算子會計算和的序數值之間的差異x
y
,而結果的型別則是列舉的基礎類型。In other words, the operator computes the difference between the ordinal values ofx
andy
, and the type of the result is the underlying type of the enumeration.E operator -(E x, U y);
這個運算子的評估方式完全相同
(E)((U)x - y)
。This operator is evaluated exactly as(E)((U)x - y)
. 換句話說,運算子會從列舉的基礎類型減去值,並產生列舉的值。In other words, the operator subtracts a value from the underlying type of the enumeration, yielding a value of the enumeration.委派移除。Delegate removal. 每個委派型別都會隱含地提供下列預先定義的運算子,其中
D
是委派型別:Every delegate type implicitly provides the following predefined operator, whereD
is the delegate type:D operator -(D x, D y);
二元
-
運算子會在兩個運算元都屬於某個委派類型時,執行委派移除D
。The binary-
operator performs delegate removal when both operands are of some delegate typeD
. 如果運算元有不同的委派類型,就會發生系結階段錯誤。If the operands have different delegate types, a binding-time error occurs. 如果第一個運算元是null
,則作業的結果是null
。If the first operand isnull
, the result of the operation isnull
. 否則,如果第二個運算元是null
,則運算的結果會是第一個運算元的值。Otherwise, if the second operand isnull
, then the result of the operation is the value of the first operand. 否則,這兩個運算元代表具有一個或多個專案的調用清單 () 委派 宣告,而結果是新的調用清單,其中包含第一個運算元的清單,其中包含第二個運算元的專案,前提是第二個運算元的清單是第一個運算元的適當連續子清單。Otherwise, both operands represent invocation lists (Delegate declarations) having one or more entries, and the result is a new invocation list consisting of the first operand's list with the second operand's entries removed from it, provided the second operand's list is a proper contiguous sublist of the first's. (判斷子清單是否相等,對應的專案會與委派等號比較運算子的比較, (委派等 號比較運算子) ) 。否則,結果就是左運算元的值。(To determine sublist equality, corresponding entries are compared as for the delegate equality operator (Delegate equality operators).) Otherwise, the result is the value of the left operand. 進程中的兩個運算元清單都沒有變更。Neither of the operands' lists is changed in the process. 如果第二個運算元的清單與第一個運算元清單中連續專案的多個清單子相符,則會移除最右邊相符的連續專案子清單。If the second operand's list matches multiple sublists of contiguous entries in the first operand's list, the right-most matching sublist of contiguous entries is removed. 如果移除導致空白清單,則結果是null
。If removal results in an empty list, the result isnull
. 例如:For example:delegate void D(int x); class C { public static void M1(int i) { /* ... */ } public static void M2(int i) { /* ... */ } } class Test { static void Main() { D cd1 = new D(C.M1); D cd2 = new D(C.M2); D cd3 = cd1 + cd2 + cd2 + cd1; // M1 + M2 + M2 + M1 cd3 -= cd1; // => M1 + M2 + M2 cd3 = cd1 + cd2 + cd2 + cd1; // M1 + M2 + M2 + M1 cd3 -= cd1 + cd2; // => M2 + M1 cd3 = cd1 + cd2 + cd2 + cd1; // M1 + M2 + M2 + M1 cd3 -= cd2 + cd2; // => M1 + M1 cd3 = cd1 + cd2 + cd2 + cd1; // M1 + M2 + M2 + M1 cd3 -= cd2 + cd1; // => M1 + M2 cd3 = cd1 + cd2 + cd2 + cd1; // M1 + M2 + M2 + M1 cd3 -= cd1 + cd1; // => M1 + M2 + M2 + M1 } }
移位運算子Shift operators
<<
和 >>
運算子用來執行位移位作業。The <<
and >>
operators are used to perform bit shifting operations.
shift_expression
: additive_expression
| shift_expression '<<' additive_expression
| shift_expression right_shift additive_expression
;
如果 shift_expression 的運算元具有編譯時間型別 dynamic
,則運算式會動態系結 (動態繫結) 。If an operand of a shift_expression has the compile-time type dynamic
, then the expression is dynamically bound (Dynamic binding). 在此情況下,運算式的編譯時間型別是 dynamic
,而且下面所述的解析將會在執行時間使用具有編譯時間類型之運算元的執行時間型別進行 dynamic
。In this case the compile-time type of the expression is dynamic
, and the resolution described below will take place at run-time using the run-time type of those operands that have the compile-time type dynamic
.
若為表單或的 x << count
運算 x >> count
,二元運算子多載解析 (二元運算子 多載解析) 套用至選取特定的運算子執行。For an operation of the form x << count
or x >> count
, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. 運算元會轉換成所選運算子的參數類型,而結果的型別則是運算子的傳回型別。The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.
宣告多載移位運算子時,第一個運算元的類型必須一律為包含運算子宣告的類別或結構,而第二個運算元的類型必須一律為 int
。When declaring an overloaded shift operator, the type of the first operand must always be the class or struct containing the operator declaration, and the type of the second operand must always be int
.
預先定義的移位運算子如下所示。The predefined shift operators are listed below.
左移:Shift left:
int operator <<(int x, int count); uint operator <<(uint x, int count); long operator <<(long x, int count); ulong operator <<(ulong x, int count);
<<
運算子會x
向左移一些計算的位數,如下所述。The<<
operator shiftsx
left by a number of bits computed as described below.會捨棄結果型別範圍之外的高序位位
x
,其餘的位會左移,而且低序位空白位位置會設定為零。The high-order bits outside the range of the result type ofx
are discarded, the remaining bits are shifted left, and the low-order empty bit positions are set to zero.右移:Shift right:
int operator >>(int x, int count); uint operator >>(uint x, int count); long operator >>(long x, int count); ulong operator >>(ulong x, int count);
>>
運算子會x
由計算的位數右移,如下所述。The>>
operator shiftsx
right by a number of bits computed as described below.當
x
的型別為int
或時long
,會捨棄的低序位位x
,其餘的位會右移,而且如果x
是負數,則高序位的空白位位置會設定為零x
。Whenx
is of typeint
orlong
, the low-order bits ofx
are discarded, the remaining bits are shifted right, and the high-order empty bit positions are set to zero ifx
is non-negative and set to one ifx
is negative.當
x
的類型為uint
或時ulong
,會捨棄的低序位位x
,其餘的位會右移,而高序位的空白位位置會設定為零。Whenx
is of typeuint
orulong
, the low-order bits ofx
are discarded, the remaining bits are shifted right, and the high-order empty bit positions are set to zero.
針對預先定義的運算子,會計算要移位的位數,如下所示:For the predefined operators, the number of bits to shift is computed as follows:
- 當的型別
x
為int
或時uint
,會由的低序位五位指定移位元數目count
。When the type ofx
isint
oruint
, the shift count is given by the low-order five bits ofcount
. 換句話說,會從計算移位元數目count & 0x1F
。In other words, the shift count is computed fromcount & 0x1F
. - 當的型別
x
為long
或時ulong
,會由的低序位六位指定移位元數目count
。When the type ofx
islong
orulong
, the shift count is given by the low-order six bits ofcount
. 換句話說,會從計算移位元數目count & 0x3F
。In other words, the shift count is computed fromcount & 0x3F
.
如果產生的移位元數目為零,則移位運算子只會傳回的值 x
。If the resulting shift count is zero, the shift operators simply return the value of x
.
移位作業永遠不會造成溢位,並且在和內容中產生相同的結果 checked
unchecked
。Shift operations never cause overflows and produce the same results in checked
and unchecked
contexts.
當運算子的左運算元 >>
是帶正負號的整數類資料型別時,運算子會對運算元的正負號 (的正負號,將運算元的正負號位) 的值傳播到高序位的空白位位置。When the left operand of the >>
operator is of a signed integral type, the operator performs an arithmetic shift right wherein the value of the most significant bit (the sign bit) of the operand is propagated to the high-order empty bit positions. 當運算子的左運算元 >>
是不帶正負號的整數類資料類型時,運算子會執行邏輯右移,其中高序位空白位位置一律設定為零。When the left operand of the >>
operator is of an unsigned integral type, the operator performs a logical shift right wherein high-order empty bit positions are always set to zero. 若要執行從運算元類型推斷而來的相反運算,可以使用明確轉換。To perform the opposite operation of that inferred from the operand type, explicit casts can be used. 例如,如果 x
是類型的變數 int
,則作業會 unchecked((int)((uint)x >> y))
執行的邏輯右移 x
。For example, if x
is a variable of type int
, the operation unchecked((int)((uint)x >> y))
performs a logical shift right of x
.
關係和類型測試運算子Relational and type-testing operators
、、、、、 ==
!=
<
>
<=
>=
is
和 as
運算子稱為關聯式和型別測試運算子。The ==
, !=
, <
, >
, <=
, >=
, is
and as
operators are called the relational and type-testing operators.
relational_expression
: shift_expression
| relational_expression '<' shift_expression
| relational_expression '>' shift_expression
| relational_expression '<=' shift_expression
| relational_expression '>=' shift_expression
| relational_expression 'is' type
| relational_expression 'as' type
;
equality_expression
: relational_expression
| equality_expression '==' relational_expression
| equality_expression '!=' relational_expression
;
is
運算子會在 as 運算子中描述,而 as
運算子則是在as 運算子中描述。The is
operator is described in The is operator and the as
operator is described in The as operator.
==
、、 !=
<
、 >
<=
和 >=
運算子為 比較運算子。The ==
, !=
, <
, >
, <=
and >=
operators are comparison operators.
如果比較運算子的運算元具有編譯時間型別 dynamic
,則運算式會動態繫結 (動態繫結) 。If an operand of a comparison operator has the compile-time type dynamic
, then the expression is dynamically bound (Dynamic binding). 在此情況下,運算式的編譯時間型別是 dynamic
,而且下面所述的解析將會在執行時間使用具有編譯時間類型之運算元的執行時間型別進行 dynamic
。In this case the compile-time type of the expression is dynamic
, and the resolution described below will take place at run-time using the run-time type of those operands that have the compile-time type dynamic
.
若為表單 op 的作業 x
y
,其中 op 是比較運算子,則會套用多載解析 (二元運算子多載解析) 套用至選取特定的運算子執行。For an operation of the form x
op y
, where op is a comparison operator, overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. 運算元會轉換成所選運算子的參數類型,而結果的型別則是運算子的傳回型別。The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.
預先定義的比較運算子會在下列各節中說明。The predefined comparison operators are described in the following sections. 所有預先定義的比較運算子都會傳回型別的結果 bool
,如下表所述。All predefined comparison operators return a result of type bool
, as described in the following table.
運算Operation | 結果Result |
---|---|
x == y |
true 如果 x 等於,則為 y , false 否則為。true if x is equal to y , false otherwise |
x != y |
true 如果不 x 等於,則為 y , false 否則為。true if x is not equal to y , false otherwise |
x < y |
若 x 小於 y 則為 true ;否則為 false true if x is less than y , false otherwise |
x > y |
若 x 大於 y 則為 true ;否則為 false true if x is greater than y , false otherwise |
x <= y |
若 x 小於或等於 y 則為 true ;否則為 false true if x is less than or equal to y , false otherwise |
x >= y |
若 x 大於或等於 y 則為 true ;否則為 false true if x is greater than or equal to y , false otherwise |
整數比較運算子Integer comparison operators
預先定義的整數比較運算子如下:The predefined integer comparison operators are:
bool operator ==(int x, int y);
bool operator ==(uint x, uint y);
bool operator ==(long x, long y);
bool operator ==(ulong x, ulong y);
bool operator !=(int x, int y);
bool operator !=(uint x, uint y);
bool operator !=(long x, long y);
bool operator !=(ulong x, ulong y);
bool operator <(int x, int y);
bool operator <(uint x, uint y);
bool operator <(long x, long y);
bool operator <(ulong x, ulong y);
bool operator >(int x, int y);
bool operator >(uint x, uint y);
bool operator >(long x, long y);
bool operator >(ulong x, ulong y);
bool operator <=(int x, int y);
bool operator <=(uint x, uint y);
bool operator <=(long x, long y);
bool operator <=(ulong x, ulong y);
bool operator >=(int x, int y);
bool operator >=(uint x, uint y);
bool operator >=(long x, long y);
bool operator >=(ulong x, ulong y);
每個運算子都會比較兩個整數運算元的數值,並傳回 bool
值,指出特定關聯性是 true
或 false
。Each of these operators compares the numeric values of the two integer operands and returns a bool
value that indicates whether the particular relation is true
or false
.
浮點數比較運算子Floating-point comparison operators
預先定義的浮點比較運算子如下:The predefined floating-point comparison operators are:
bool operator ==(float x, float y);
bool operator ==(double x, double y);
bool operator !=(float x, float y);
bool operator !=(double x, double y);
bool operator <(float x, float y);
bool operator <(double x, double y);
bool operator >(float x, float y);
bool operator >(double x, double y);
bool operator <=(float x, float y);
bool operator <=(double x, double y);
bool operator >=(float x, float y);
bool operator >=(double x, double y);
運算子會根據 IEEE 754 標準的規則來比較運算元:The operators compare the operands according to the rules of the IEEE 754 standard:
如果任一個運算元為 NaN,則結果為
false
所有運算子!=
,但結果為true
。If either operand is NaN, the result isfalse
for all operators except!=
, for which the result istrue
. 針對任何兩個運算元,x != y
一律會產生與相同的結果!(x == y)
。For any two operands,x != y
always produces the same result as!(x == y)
. 不過,當一個或兩個運算元都是 NaN 時,<
、>
、<=
和>=
運算子不會產生與相反運算子的邏輯否定相同的結果。However, when one or both operands are NaN, the<
,>
,<=
, and>=
operators do not produce the same results as the logical negation of the opposite operator. 例如,如果的任一個x
y
是 NaN,則為x < y
false
,但!(x >= y)
為true
。For example, if either ofx
andy
is NaN, thenx < y
isfalse
, but!(x >= y)
istrue
.當兩個運算元都不是 NaN 時,運算子會比較兩個浮點數運算元的值與順序相關When neither operand is NaN, the operators compare the values of the two floating-point operands with respect to the ordering
-inf < -max < ... < -min < -0.0 == +0.0 < +min < ... < +max < +inf
其中
min
和max
是可依給定浮點數格式表示的最小和最大正有限值。wheremin
andmax
are the smallest and largest positive finite values that can be represented in the given floating-point format. 此順序值得注意的影響如下:Notable effects of this ordering are:- 負零和正零會視為相等。Negative and positive zeros are considered equal.
- 負無限大會被視為小於所有其他值,但等於另一個負無限大。A negative infinity is considered less than all other values, but equal to another negative infinity.
- 正無限大視為大於所有其他值,但等於另一個正無限大。A positive infinity is considered greater than all other values, but equal to another positive infinity.
小數比較運算子Decimal comparison operators
預先定義的十進位比較運算子如下:The predefined decimal comparison operators are:
bool operator ==(decimal x, decimal y);
bool operator !=(decimal x, decimal y);
bool operator <(decimal x, decimal y);
bool operator >(decimal x, decimal y);
bool operator <=(decimal x, decimal y);
bool operator >=(decimal x, decimal y);
每個運算子都會比較兩個十進位運算元的數值,並傳回一個 bool
值,指出特定關聯性為 true
或 false
。Each of these operators compares the numeric values of the two decimal operands and returns a bool
value that indicates whether the particular relation is true
or false
. 每個小數比較相當於使用類型的對應關聯式或等號比較運算子 System.Decimal
。Each decimal comparison is equivalent to using the corresponding relational or equality operator of type System.Decimal
.
布林等號比較運算子Boolean equality operators
預先定義的布林相等運算子如下:The predefined boolean equality operators are:
bool operator ==(bool x, bool y);
bool operator !=(bool x, bool y);
的結果為,如果和都是 ==
true
x
y
true
或 x
,而且和 y
都是, false
則為。The result of ==
is true
if both x
and y
are true
or if both x
and y
are false
. 否則,結果為 false
。Otherwise, the result is false
.
的結果為,如果和都是 !=
false
x
y
true
或 x
,而且和 y
都是, false
則為。The result of !=
is false
if both x
and y
are true
or if both x
and y
are false
. 否則,結果為 true
。Otherwise, the result is true
. 當運算元的類型為時 bool
, !=
運算子會產生與運算子相同的結果 ^
。When the operands are of type bool
, the !=
operator produces the same result as the ^
operator.
列舉比較運算子Enumeration comparison operators
每個列舉類型都會隱含地提供下列預先定義的比較運算子:Every enumeration type implicitly provides the following predefined comparison operators:
bool operator ==(E x, E y);
bool operator !=(E x, E y);
bool operator <(E x, E y);
bool operator >(E x, E y);
bool operator <=(E x, E y);
bool operator >=(E x, E y);
評估的結果 x op y
(其中 x
和 y
是具有基礎類型之列舉型別的運算式), E
U
而 op
是其中一個比較運算子,與評估完全相同 ((U)x) op ((U)y)
。The result of evaluating x op y
, where x
and y
are expressions of an enumeration type E
with an underlying type U
, and op
is one of the comparison operators, is exactly the same as evaluating ((U)x) op ((U)y)
. 換句話說,列舉型別比較運算子只會比較兩個運算元的基礎整數值。In other words, the enumeration type comparison operators simply compare the underlying integral values of the two operands.
參考型別等號比較運算子Reference type equality operators
預先定義的參考型別等號比較運算子為:The predefined reference type equality operators are:
bool operator ==(object x, object y);
bool operator !=(object x, object y);
運算子會傳回比較兩個參考是否相等或不相等的結果。The operators return the result of comparing the two references for equality or non-equality.
由於預先定義的參考型別等號比較運算子接受型別的運算元 object
,因此它們會套用至所有未宣告適用 operator ==
和成員的類型 operator !=
。Since the predefined reference type equality operators accept operands of type object
, they apply to all types that do not declare applicable operator ==
and operator !=
members. 相反地,任何適用的使用者定義等號比較運算子都會有效地隱藏預先定義的參考型別等號比較運算子。Conversely, any applicable user-defined equality operators effectively hide the predefined reference type equality operators.
預先定義的參考型別等號比較運算子需要下列其中一項:The predefined reference type equality operators require one of the following:
- 這兩個運算元都是已知為 reference_type 或常值之類型的值
null
。Both operands are a value of a type known to be a reference_type or the literalnull
. 此外,明確參考轉換 (明確參考 轉換) 存在於任一運算元的類型與另一個運算元的類型之間。Furthermore, an explicit reference conversion (Explicit reference conversions) exists from the type of either operand to the type of the other operand. - 其中一個運算元是型別的值,
T
其中T
是 type_parameter ,另一個運算元是常值null
。One operand is a value of typeT
whereT
is a type_parameter and the other operand is the literalnull
. 此外T
,也沒有實數值型別條件約束。FurthermoreT
does not have the value type constraint.
除非其中一個條件為 true,否則會發生系結階段錯誤。Unless one of these conditions are true, a binding-time error occurs. 這些規則的顯著含意如下:Notable implications of these rules are:
- 這是系結階段錯誤,可使用預先定義的參考型別等號比較運算子來比較已知在系結時間不同的兩個參考。It is a binding-time error to use the predefined reference type equality operators to compare two references that are known to be different at binding-time. 例如,如果運算元的系結時間型別是兩個類別型別
A
,B
而且也不是A
B
衍生自另一個類別,則這兩個運算元將無法參考相同的物件。For example, if the binding-time types of the operands are two class typesA
andB
, and if neitherA
norB
derives from the other, then it would be impossible for the two operands to reference the same object. 因此,作業會被視為系結階段錯誤。Thus, the operation is considered a binding-time error. - 預先定義的參考型別等號比較運算子不允許比較實值型別運算元。The predefined reference type equality operators do not permit value type operands to be compared. 因此,除非結構類型宣告自己的等號比較運算子,否則不可能比較該結構類型的值。Therefore, unless a struct type declares its own equality operators, it is not possible to compare values of that struct type.
- 預先定義的參考型別等號比較運算子永遠不會導致其運算元發生「裝箱」作業。The predefined reference type equality operators never cause boxing operations to occur for their operands. 執行這類的裝箱作業並不具意義,因為對新配置的已封裝實例的參考必須與其他所有參考不同。It would be meaningless to perform such boxing operations, since references to the newly allocated boxed instances would necessarily differ from all other references.
- 如果將類型參數類型的運算元
T
與進行比較null
,且執行時間類型為實T
值型別,則比較結果為false
。If an operand of a type parameter typeT
is compared tonull
, and the run-time type ofT
is a value type, the result of the comparison isfalse
.
下列範例會檢查不受限制之類型參數類型的引數是否為 null
。The following example checks whether an argument of an unconstrained type parameter type is null
.
class C<T>
{
void F(T x) {
if (x == null) throw new ArgumentNullException();
...
}
}
x == null
即使可以表示實值型別,也可以使用此結構 T
,而結果只是定義為 false
實 T
值型別。The x == null
construct is permitted even though T
could represent a value type, and the result is simply defined to be false
when T
is a value type.
若為表單的作業 x == y
x != y
,或(如果有任何適用 operator ==
或存在),運算子多載 operator !=
解析 (二元運算子 多載解析) 規則會選取該運算子,而不是預先定義的參考型別等號比較運算子。For an operation of the form x == y
or x != y
, if any applicable operator ==
or operator !=
exists, the operator overload resolution (Binary operator overload resolution) rules will select that operator instead of the predefined reference type equality operator. 不過,您一律可以明確地將一個或兩個運算元轉換成類型,來選取預先定義的參考型別等號比較運算子 object
。However, it is always possible to select the predefined reference type equality operator by explicitly casting one or both of the operands to type object
. 範例The example
using System;
class Test
{
static void Main() {
string s = "Test";
string t = string.Copy(s);
Console.WriteLine(s == t);
Console.WriteLine((object)s == t);
Console.WriteLine(s == (object)t);
Console.WriteLine((object)s == (object)t);
}
}
產生下列輸出produces the output
True
False
False
False
s
和 t
變數參考兩個不同 string
的實例,其中包含相同的字元。The s
and t
variables refer to two distinct string
instances containing the same characters. 第一個比較輸出的原因是, True
當兩個運算元的類型為時,會選取預先定義的字串相等運算子 (字串相等運算子) string
。The first comparison outputs True
because the predefined string equality operator (String equality operators) is selected when both operands are of type string
. 其餘的比較會比較所有輸出 False
,因為當其中一個或兩個運算元的類型為時,會選取預先定義的參考型別等號比較運算子 object
。The remaining comparisons all output False
because the predefined reference type equality operator is selected when one or both of the operands are of type object
.
請注意,上述技巧對實值型別沒有意義。Note that the above technique is not meaningful for value types. 範例The example
class Test
{
static void Main() {
int i = 123;
int j = 123;
System.Console.WriteLine((object)i == (object)j);
}
}
輸出 False
,因為轉換會建立兩個不同的已框值實例的參考 int
。outputs False
because the casts create references to two separate instances of boxed int
values.
字串等號比較運算子String equality operators
預先定義的字串等號比較運算子如下:The predefined string equality operators are:
bool operator ==(string x, string y);
bool operator !=(string x, string y);
string
當下列其中一項為真時,兩個值會被視為相等:Two string
values are considered equal when one of the following is true:
- 這兩個值都是
null
。Both values arenull
. - 這兩個值都是在每個字元位置都有相同長度和相同字元之字串實例的非 null 參考。Both values are non-null references to string instances that have identical lengths and identical characters in each character position.
字串等號比較運算子比較字串值,而不是字串參考。The string equality operators compare string values rather than string references. 當兩個不同的字串實例包含完全相同的字元序列時,字串的值會相等,但參考不同。When two separate string instances contain the exact same sequence of characters, the values of the strings are equal, but the references are different. 如 參考型別等號比較運算子中所述,參考型別等號比較運算子可以用來比較字串參考,而不是字串值。As described in Reference type equality operators, the reference type equality operators can be used to compare string references instead of string values.
委派等號比較運算子Delegate equality operators
每個委派型別都會隱含地提供下列預先定義的比較運算子:Every delegate type implicitly provides the following predefined comparison operators:
bool operator ==(System.Delegate x, System.Delegate y);
bool operator !=(System.Delegate x, System.Delegate y);
兩個委派實例的視為相同,如下所示:Two delegate instances are considered equal as follows:
- 如果其中一個委派實例為
null
,則它們都相等,而且只有在兩者皆為時null
。If either of the delegate instances isnull
, they are equal if and only if both arenull
. - 如果委派有不同的執行時間類型,它們永遠不會相等。If the delegates have different run-time type they are never equal.
- 如果這兩個委派實例都有一個調用清單 (委派 宣告) ,則只有在其調用清單的長度相同,且一個調用清單中的每個專案都 (等於對應專案(依序在其他的調用清單中)) 對應專案的情況下,才會相等。If both of the delegate instances have an invocation list (Delegate declarations), those instances are equal if and only if their invocation lists are the same length, and each entry in one's invocation list is equal (as defined below) to the corresponding entry, in order, in the other's invocation list.
下列規則會管理調用清單專案的相等:The following rules govern the equality of invocation list entries:
- 如果兩個調用清單專案都參考相同的靜態方法,則專案會相等。If two invocation list entries both refer to the same static method then the entries are equal.
- 如果兩個調用清單專案都參考相同目標物件上的相同非靜態方法 (如參考等號比較運算子所定義) 則專案相等。If two invocation list entries both refer to the same non-static method on the same target object (as defined by the reference equality operators) then the entries are equal.
- 在以語義相同的 anonymous_method_expression s 或 lambda_expression s 的評估所產生的調用清單專案中,具有相同 (可能會有空白) 的已捕捉外部變數實例集 (但不需要) 相等。Invocation list entries produced from evaluation of semantically identical anonymous_method_expression s or lambda_expression s with the same (possibly empty) set of captured outer variable instances are permitted (but not required) to be equal.
等號比較運算子和 nullEquality operators and null
==
And !=
運算子允許一個運算元成為可為 null 型別的值,另一個運算元為 null
常值,即使沒有任何預先定義或使用者定義的運算子 (在 unlifted 或提升表單中) 存在於作業中。The ==
and !=
operators permit one operand to be a value of a nullable type and the other to be the null
literal, even if no predefined or user-defined operator (in unlifted or lifted form) exists for the operation.
針對其中一個表單的操作For an operation of one of the forms
x == null
null == x
x != null
null != x
其中 x
是可為 null 之類型的運算式,如果運算子多載解析 (二元運算子 多載解析) 找不到適用的運算子,則會改為從的屬性計算結果 HasValue
x
。where x
is an expression of a nullable type, if operator overload resolution (Binary operator overload resolution) fails to find an applicable operator, the result is instead computed from the HasValue
property of x
. 具體來說,前兩個形式會轉譯成 !x.HasValue
,最後兩個形式會轉譯為 x.HasValue
。Specifically, the first two forms are translated into !x.HasValue
, and last two forms are translated into x.HasValue
.
is 運算子The is operator
is
運算子用來動態檢查物件的執行時間類型是否與指定的類型相容。The is
operator is used to dynamically check if the run-time type of an object is compatible with a given type. 作業的結果 E is T
(其中 E
是運算式且 T
為型別)是一個布林值,指出是否可以透過 E
T
參考轉換、裝箱轉換或取消加入的轉換,成功地將轉換成型別。The result of the operation E is T
, where E
is an expression and T
is a type, is a boolean value indicating whether E
can successfully be converted to type T
by a reference conversion, a boxing conversion, or an unboxing conversion. 在將型別引數替換為所有型別參數之後,此作業會評估如下:The operation is evaluated as follows, after type arguments have been substituted for all type parameters:
- 如果
E
是匿名函式,就會發生編譯時期錯誤IfE
is an anonymous function, a compile-time error occurs - 如果
E
是方法群組或null
常值,如果的類型E
是參考型別或可為 null 的型別,而且的值E
為 null,則結果為 false。IfE
is a method group or thenull
literal, of if the type ofE
is a reference type or a nullable type and the value ofE
is null, the result is false. - 否則,讓我們
D
以如下方式表示動態類型E
:Otherwise, letD
represent the dynamic type ofE
as follows:- 如果的型別
E
是參考型別,D
則是實例參考的執行時間型別E
。If the type ofE
is a reference type,D
is the run-time type of the instance reference byE
. - 如果的型別
E
是可為 null 的型別,D
就是可為 null 型別的基礎型別。If the type ofE
is a nullable type,D
is the underlying type of that nullable type. - 如果的型別
E
是不可為 null 的實值型別,D
就是的型別E
。If the type ofE
is a non-nullable value type,D
is the type ofE
.
- 如果的型別
- 作業的結果取決於和,如下所示
D
T
:The result of the operation depends onD
andT
as follows:- 如果
T
是參考型別,則如果D
和是T
相同的型別,而且如果D
是的參考型別和從的隱含參考轉換D
T
,或者是實值型別,D
而且從轉換D
成 exists 的T
,則結果為 true。IfT
is a reference type, the result is true ifD
andT
are the same type, ifD
is a reference type and an implicit reference conversion fromD
toT
exists, or ifD
is a value type and a boxing conversion fromD
toT
exists. - 如果
T
是可為 null 的型別,則如果D
是的基礎型別,則結果為 trueT
。IfT
is a nullable type, the result is true ifD
is the underlying type ofT
. - 如果
T
是不可為 null 的實值型別,則如果D
和是相同的型別,則結果為 trueT
。IfT
is a non-nullable value type, the result is true ifD
andT
are the same type. - 否則,結果為 false。Otherwise, the result is false.
- 如果
請注意,運算子不會考慮使用者定義的轉換 is
。Note that user defined conversions, are not considered by the is
operator.
as 運算子The as operator
as
運算子用來將值明確轉換為指定的參考型別或可為 null 的型別。The as
operator is used to explicitly convert a value to a given reference type or nullable type. 不同于 cast 運算式 (cast 運算式) , as
運算子永遠不會擲回例外狀況。Unlike a cast expression (Cast expressions), the as
operator never throws an exception. 相反地,如果無法指定轉換,則產生的值為 null
。Instead, if the indicated conversion is not possible, the resulting value is null
.
在表單的作業中 E as T
, E
必須是運算式且 T
必須是參考型別、已知為參考型別的類型參數,或可為 null 的型別。In an operation of the form E as T
, E
must be an expression and T
must be a reference type, a type parameter known to be a reference type, or a nullable type. 此外,至少必須符合下列其中一項條件,否則會發生編譯時期錯誤:Furthermore, at least one of the following must be true, or otherwise a compile-time error occurs:
- 身分識別 (身分 識別轉換) 、隱含可為 null 的 (隱含的可 為 null 轉換) 、隱含參考 (隱含參考轉換) 、將 (的 隱含參考轉換) 、明確可為 null ( 明確參考轉換) 的明確參考,或取消的轉換 (取消的轉換) 取消的轉換 轉換 (轉換存在於
E
至T
。An identity (Identity conversion), implicit nullable (Implicit nullable conversions), implicit reference (Implicit reference conversions), boxing (Boxing conversions), explicit nullable (Explicit nullable conversions), explicit reference (Explicit reference conversions), or unboxing (Unboxing conversions) conversion exists fromE
toT
. - 或的型
E
別T
是開放式型別。The type ofE
orT
is an open type. E
這是null
常值。E
is thenull
literal.
如果的編譯時間型別 E
不是 dynamic
,則作業 E as T
產生的結果與If the compile-time type of E
is not dynamic
, the operation E as T
produces the same result as
E is T ? (T)(E) : (T)null
但只會評估 E
一次。except that E
is only evaluated once. 編譯器可以優化 E as T
為最多執行一次動態類型檢查,而不是上述擴充所隱含的兩個動態類型檢查。The compiler can be expected to optimize E as T
to perform at most one dynamic type check as opposed to the two dynamic type checks implied by the expansion above.
如果的編譯時間類型 E
是,則 dynamic
與 cast 運算子不同的是, as
運算子不會動態系結 (動態繫結) 。If the compile-time type of E
is dynamic
, unlike the cast operator the as
operator is not dynamically bound (Dynamic binding). 因此,在此情況下的擴充是:Therefore the expansion in this case is:
E is T ? (T)(object)(E) : (T)null
請注意,某些轉換(例如使用者定義的轉換)無法與運算子搭配 as
使用,而應該改用 cast 運算式來執行。Note that some conversions, such as user defined conversions, are not possible with the as
operator and should instead be performed using cast expressions.
在範例中In the example
class X
{
public string F(object o) {
return o as string; // OK, string is a reference type
}
public T G<T>(object o) where T: Attribute {
return o as T; // Ok, T has a class constraint
}
public U H<U>(object o) {
return o as U; // Error, U is unconstrained
}
}
的型別 T
參數 G
已知為參考型別,因為它具有類別條件約束。the type parameter T
of G
is known to be a reference type, because it has the class constraint. 但是的型別參數 U
H
不是,因此不 as
允許在中使用運算子 H
。The type parameter U
of H
is not however; hence the use of the as
operator in H
is disallowed.
邏輯運算子Logical operators
&
、 ^
和 |
運算子稱為邏輯運算子。The &
, ^
, and |
operators are called the logical operators.
and_expression
: equality_expression
| and_expression '&' equality_expression
;
exclusive_or_expression
: and_expression
| exclusive_or_expression '^' and_expression
;
inclusive_or_expression
: exclusive_or_expression
| inclusive_or_expression '|' exclusive_or_expression
;
如果邏輯運算子的運算元具有編譯時間型別 dynamic
,則運算式會動態繫結 (動態繫結) 。If an operand of a logical operator has the compile-time type dynamic
, then the expression is dynamically bound (Dynamic binding). 在此情況下,運算式的編譯時間型別是 dynamic
,而且下面所述的解析將會在執行時間使用具有編譯時間類型之運算元的執行時間型別進行 dynamic
。In this case the compile-time type of the expression is dynamic
, and the resolution described below will take place at run-time using the run-time type of those operands that have the compile-time type dynamic
.
若為表單的作業 x op y
(其中 op
是其中一個邏輯運算子),則會套用多載解析 (二元運算子 多載解析) 套用至選取特定的運算子執行。For an operation of the form x op y
, where op
is one of the logical operators, overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. 運算元會轉換成所選運算子的參數類型,而結果的型別則是運算子的傳回型別。The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.
預先定義的邏輯運算子會在下列各節中說明。The predefined logical operators are described in the following sections.
整數邏輯運算子Integer logical operators
預先定義的整數邏輯運算子為:The predefined integer logical operators are:
int operator &(int x, int y);
uint operator &(uint x, uint y);
long operator &(long x, long y);
ulong operator &(ulong x, ulong y);
int operator |(int x, int y);
uint operator |(uint x, uint y);
long operator |(long x, long y);
ulong operator |(ulong x, ulong y);
int operator ^(int x, int y);
uint operator ^(uint x, uint y);
long operator ^(long x, long y);
ulong operator ^(ulong x, ulong y);
&
運算子會計算兩個運算元的位邏輯 AND
,運算子會計算兩個運算元的位邏輯 |
OR
,而 ^
運算子會計算兩個運算元的位邏輯互斥 OR
。The &
operator computes the bitwise logical AND
of the two operands, the |
operator computes the bitwise logical OR
of the two operands, and the ^
operator computes the bitwise logical exclusive OR
of the two operands. 這些作業不可能有溢位。No overflows are possible from these operations.
列舉邏輯運算子Enumeration logical operators
每個列舉類型都會 E
隱含地提供下列預先定義的邏輯運算子:Every enumeration type E
implicitly provides the following predefined logical operators:
E operator &(E x, E y);
E operator |(E x, E y);
E operator ^(E x, E y);
評估的結果 x op y
(其中 x
和 y
是具有基礎類型之列舉類型的運算式), E
U
而 op
是其中一個邏輯運算子,與評估完全相同 (E)((U)x op (U)y)
。The result of evaluating x op y
, where x
and y
are expressions of an enumeration type E
with an underlying type U
, and op
is one of the logical operators, is exactly the same as evaluating (E)((U)x op (U)y)
. 換句話說,列舉型別邏輯運算子只會在兩個運算元的基礎類型上執行邏輯運算。In other words, the enumeration type logical operators simply perform the logical operation on the underlying type of the two operands.
布林值邏輯運算子Boolean logical operators
預先定義的布林值邏輯運算子如下:The predefined boolean logical operators are:
bool operator &(bool x, bool y);
bool operator |(bool x, bool y);
bool operator ^(bool x, bool y);
若 x
及 y
皆為 true
,那麼 x & y
的結果會是 true
。The result of x & y
is true
if both x
and y
are true
. 否則,結果為 false
。Otherwise, the result is false
.
x | y
true
如果 x
或 y
為,則的結果為 true
。The result of x | y
is true
if either x
or y
is true
. 否則,結果為 false
。Otherwise, the result is false
.
的結果 x ^ y
為, true
如果 x
為 true
y
,且為 false
,或者 x
為 false
且 y
為 true
。The result of x ^ y
is true
if x
is true
and y
is false
, or x
is false
and y
is true
. 否則,結果為 false
。Otherwise, the result is false
. 當運算元的類型為時 bool
, ^
運算子會計算與運算子相同的結果 !=
。When the operands are of type bool
, the ^
operator computes the same result as the !=
operator.
可為 null 的布林值邏輯運算子Nullable boolean logical operators
可為 null 的布林值型別 bool?
可以代表三個值:、 true
false
和 null
,而且在概念上類似于 SQL 中用於布林運算式的三值型別。The nullable boolean type bool?
can represent three values, true
, false
, and null
, and is conceptually similar to the three-valued type used for boolean expressions in SQL. 為了確保和運算元的運算子所產生的結果 &
|
bool?
與 SQL 的三值邏輯一致,會提供下列預先定義的運算子:To ensure that the results produced by the &
and |
operators for bool?
operands are consistent with SQL's three-valued logic, the following predefined operators are provided:
bool? operator &(bool? x, bool? y);
bool? operator |(bool? x, bool? y);
下表列出這些運算子針對所有值、和組合所產生的結果 true
false
null
。The following table lists the results produced by these operators for all combinations of the values true
, false
, and null
.
x |
y |
x & y |
x | y |
---|---|---|---|
true |
true |
true |
true |
true |
false |
false |
true |
true |
null |
null |
true |
false |
true |
false |
true |
false |
false |
false |
false |
false |
null |
false |
null |
null |
true |
null |
true |
null |
false |
false |
null |
null |
null |
null |
null |
條件邏輯運算子Conditional logical operators
&&
和 ||
運算子稱為條件邏輯運算子。The &&
and ||
operators are called the conditional logical operators. 它們也稱為「短路」邏輯運算子。They are also called the "short-circuiting" logical operators.
conditional_and_expression
: inclusive_or_expression
| conditional_and_expression '&&' inclusive_or_expression
;
conditional_or_expression
: conditional_and_expression
| conditional_or_expression '||' conditional_and_expression
;
&&
和 ||
運算子是和運算子的條件式 &
版本 |
:The &&
and ||
operators are conditional versions of the &
and |
operators:
- 作業會
x && y
對應至作業x & y
,但只有在y
不是時才會評估x
false
。The operationx && y
corresponds to the operationx & y
, except thaty
is evaluated only ifx
is notfalse
. - 作業會
x || y
對應至作業x | y
,但只有在y
不是時才會評估x
true
。The operationx || y
corresponds to the operationx | y
, except thaty
is evaluated only ifx
is nottrue
.
如果條件式邏輯運算子的運算元具有編譯時間型別,則 dynamic
運算式會動態繫結 (動態繫結) 。If an operand of a conditional logical operator has the compile-time type dynamic
, then the expression is dynamically bound (Dynamic binding). 在此情況下,運算式的編譯時間型別是 dynamic
,而且下面所述的解析將會在執行時間使用具有編譯時間類型之運算元的執行時間型別進行 dynamic
。In this case the compile-time type of the expression is dynamic
, and the resolution described below will take place at run-time using the run-time type of those operands that have the compile-time type dynamic
.
表單或的作業會藉由套用多載 x && y
x || y
解析 (二元運算子 多載解析) ,如同寫入作業 x & y
或 x | y
。An operation of the form x && y
or x || y
is processed by applying overload resolution (Binary operator overload resolution) as if the operation was written x & y
or x | y
. 如此一來,Then,
- 如果多載解析找不到單一最佳運算子,或多載解析選取其中一個預先定義的整數邏輯運算子,則會發生系結階段錯誤。If overload resolution fails to find a single best operator, or if overload resolution selects one of the predefined integer logical operators, a binding-time error occurs.
- 否則,如果選取的運算子是其中一個預先定義的布林值邏輯運算子 (布林值邏輯 運算子) 或可為 null 的布林值邏輯運算子 (可為 null 的布林值邏輯運算子) ,則會如 布林條件邏輯運算子中所述處理作業。Otherwise, if the selected operator is one of the predefined boolean logical operators (Boolean logical operators) or nullable boolean logical operators (Nullable boolean logical operators), the operation is processed as described in Boolean conditional logical operators.
- 否則,選取的運算子是使用者定義的運算子,且作業會依照 使用者定義的條件式邏輯運算子中的說明進行處理。Otherwise, the selected operator is a user-defined operator, and the operation is processed as described in User-defined conditional logical operators.
您無法直接多載條件式邏輯運算子。It is not possible to directly overload the conditional logical operators. 不過,由於條件式邏輯運算子是以一般邏輯運算子來評估,因此一般邏輯運算子的多載會有某些限制,也會視為條件式邏輯運算子的多載。However, because the conditional logical operators are evaluated in terms of the regular logical operators, overloads of the regular logical operators are, with certain restrictions, also considered overloads of the conditional logical operators. 這會在 使用者定義的條件式邏輯運算子中進一步說明。This is described further in User-defined conditional logical operators.
布林條件邏輯運算子Boolean conditional logical operators
當或的運算元 &&
屬於 ||
型別時 bool
,或當運算元的類型不定義適用的 operator &
或 operator |
(但是定義了隱含轉換為)時,作業 bool
的處理方式如下:When the operands of &&
or ||
are of type bool
, or when the operands are of types that do not define an applicable operator &
or operator |
, but do define implicit conversions to bool
, the operation is processed as follows:
- 運算
x && y
會評估為x ? y : false
。The operationx && y
is evaluated asx ? y : false
. 換句話說,x
會先進行評估,並轉換成型別bool
。In other words,x
is first evaluated and converted to typebool
. 然後,如果x
是true
,y
則會評估並轉換成類型bool
,而這會成為作業的結果。Then, ifx
istrue
,y
is evaluated and converted to typebool
, and this becomes the result of the operation. 否則,作業的結果為false
。Otherwise, the result of the operation isfalse
. - 運算
x || y
會評估為x ? true : y
。The operationx || y
is evaluated asx ? true : y
. 換句話說,x
會先進行評估,並轉換成型別bool
。In other words,x
is first evaluated and converted to typebool
. 然後,如果x
是,則作業的true
結果為true
。Then, ifx
istrue
, the result of the operation istrue
. 否則,y
會進行評估並轉換成類型bool
,而這會成為作業的結果。Otherwise,y
is evaluated and converted to typebool
, and this becomes the result of the operation.
使用者定義條件式邏輯運算子User-defined conditional logical operators
當或的運算元屬於宣告 &&
||
適用使用者定義或的型別時 operator &
operator |
,下列兩項都必須為 true,其中是所 T
選運算子的宣告類型:When the operands of &&
or ||
are of types that declare an applicable user-defined operator &
or operator |
, both of the following must be true, where T
is the type in which the selected operator is declared:
- 所選運算子的傳回類型和每個參數的類型必須是
T
。The return type and the type of each parameter of the selected operator must beT
. 換句話說,運算子必須計算AND
兩個型別運算元的邏輯 or 邏輯OR
T
,而且必須傳回型別的結果T
。In other words, the operator must compute the logicalAND
or the logicalOR
of two operands of typeT
, and must return a result of typeT
. T
必須包含和的operator true
宣告operator false
。T
must contain declarations ofoperator true
andoperator false
.
如果未滿足任何一項需求,便會發生系結階段錯誤。A binding-time error occurs if either of these requirements is not satisfied. 否則, &&
會將 ||
使用者定義的 operator true
或 operator false
與選取的使用者定義運算子結合,來評估 or 運算:Otherwise, the &&
or ||
operation is evaluated by combining the user-defined operator true
or operator false
with the selected user-defined operator:
- 作業
x && y
會評估為T.false(x) ? x : T.&(x, y)
,其中T.false(x)
是在中宣告的調用,operator false
T
而且T.&(x, y)
是所選的調用operator &
。The operationx && y
is evaluated asT.false(x) ? x : T.&(x, y)
, whereT.false(x)
is an invocation of theoperator false
declared inT
, andT.&(x, y)
is an invocation of the selectedoperator &
. 換句話說,x
會先進行評估,並operator false
在結果上叫用,以判斷是否x
肯定為 false。In other words,x
is first evaluated andoperator false
is invoked on the result to determine ifx
is definitely false. 然後,如果x
肯定為 false,則作業的結果會是先前針對所計算的值x
。Then, ifx
is definitely false, the result of the operation is the value previously computed forx
. 否則,y
會進行評估,並operator &
在先前計算的值上叫用選取的值,x
並針對所計算的值,以產生作業的y
結果。Otherwise,y
is evaluated, and the selectedoperator &
is invoked on the value previously computed forx
and the value computed fory
to produce the result of the operation. - 作業
x || y
會評估為T.true(x) ? x : T.|(x, y)
,其中T.true(x)
是在中宣告的調用,operator true
T
而且T.|(x,y)
是所選的調用operator|
。The operationx || y
is evaluated asT.true(x) ? x : T.|(x, y)
, whereT.true(x)
is an invocation of theoperator true
declared inT
, andT.|(x,y)
is an invocation of the selectedoperator|
. 換句話說,x
會先進行評估,並operator true
在結果上叫用,以判斷是否x
為絕對 true。In other words,x
is first evaluated andoperator true
is invoked on the result to determine ifx
is definitely true. 然後,如果x
肯定是 true,則作業的結果會是先前針對所計算的值x
。Then, ifx
is definitely true, the result of the operation is the value previously computed forx
. 否則,y
會進行評估,並operator |
在先前計算的值上叫用選取的值,x
並針對所計算的值,以產生作業的y
結果。Otherwise,y
is evaluated, and the selectedoperator |
is invoked on the value previously computed forx
and the value computed fory
to produce the result of the operation.
在這些作業中,指定的運算式 x
只會評估一次,而指定的運算式 y
則不會只評估或評估一次。In either of these operations, the expression given by x
is only evaluated once, and the expression given by y
is either not evaluated or evaluated exactly once.
如需實和的型別範例 operator true
operator false
,請參閱 資料庫布林值型別。For an example of a type that implements operator true
and operator false
, see Database boolean type.
Null 聯合運算子The null coalescing operator
??
運算子稱為 null 聯合運算子。The ??
operator is called the null coalescing operator.
null_coalescing_expression
: conditional_or_expression
| conditional_or_expression '??' null_coalescing_expression
;
表單的 null 聯合運算式 a ?? b
a
必須是可為 null 的型別或參考型別。A null coalescing expression of the form a ?? b
requires a
to be of a nullable type or reference type. 如果 a
為非 null,則的結果為 a ?? b
, a
否則結果為 b
。If a
is non-null, the result of a ?? b
is a
; otherwise, the result is b
. b
只有當為 null 時,作業才 a
會評估。The operation evaluates b
only if a
is null.
Null 聯合運算子是右向關聯的,表示作業是由右至左分組。The null coalescing operator is right-associative, meaning that operations are grouped from right to left. 例如,表單的運算式 a ?? b ?? c
會評估為 a ?? (b ?? c)
。For example, an expression of the form a ?? b ?? c
is evaluated as a ?? (b ?? c)
. 一般情況下,表單的運算式 E1 ?? E2 ?? ... ?? En
會傳回非 null 的第一個運算元,如果所有運算元都是 null,則為 null。In general terms, an expression of the form E1 ?? E2 ?? ... ?? En
returns the first of the operands that is non-null, or null if all operands are null.
運算式的類型 a ?? b
取決於運算元上可用的隱含轉換。The type of the expression a ?? b
depends on which implicit conversions are available on the operands. 依喜好設定,的型別 a ?? b
為 A0
、 A
或 B
,其中 A
是提供類型為) 之 (的型別 a
,是指提供型別) 的 a
B
(型別 b
b
,而且 A0
A
如果 A
是可為 null 的型別,則為的基礎型別, A
否則為。In order of preference, the type of a ?? b
is A0
, A
, or B
, where A
is the type of a
(provided that a
has a type), B
is the type of b
(provided that b
has a type), and A0
is the underlying type of A
if A
is a nullable type, or A
otherwise. 具體而言, a ?? b
會以下列方式處理:Specifically, a ?? b
is processed as follows:
- 如果
A
存在,而且不是可為 null 的型別或參考型別,就會發生編譯時期錯誤。IfA
exists and is not a nullable type or a reference type, a compile-time error occurs. - 如果
b
是動態運算式,則結果類型為dynamic
。Ifb
is a dynamic expression, the result type isdynamic
. 在執行時間,a
會先評估。At run-time,a
is first evaluated. 如果不a
是 null,a
則會轉換為動態,而這會成為結果。Ifa
is not null,a
is converted to dynamic, and this becomes the result. 否則,b
會進行評估,而這會成為結果。Otherwise,b
is evaluated, and this becomes the result. - 否則,如果
A
存在,而且是可為 null 的型別,而且有隱含轉換b
A0
,則結果類型為A0
。Otherwise, ifA
exists and is a nullable type and an implicit conversion exists fromb
toA0
, the result type isA0
. 在執行時間,a
會先評估。At run-time,a
is first evaluated. 如果不a
是 null,a
則會解除包裝為類型A0
,而這會成為結果。Ifa
is not null,a
is unwrapped to typeA0
, and this becomes the result. 否則,b
會進行評估並轉換成類型A0
,而這會成為結果。Otherwise,b
is evaluated and converted to typeA0
, and this becomes the result. - 否則,如果
A
存在,而且有隱含轉換b
,則A
結果類型為A
。Otherwise, ifA
exists and an implicit conversion exists fromb
toA
, the result type isA
. 在執行時間,a
會先評估。At run-time,a
is first evaluated. 如果不a
是 null,a
就會成為結果。Ifa
is not null,a
becomes the result. 否則,b
會進行評估並轉換成類型A
,而這會成為結果。Otherwise,b
is evaluated and converted to typeA
, and this becomes the result. - 否則,如果的
b
類型B
和隱含轉換存在a
于B
,則結果類型為B
。Otherwise, ifb
has a typeB
and an implicit conversion exists froma
toB
, the result type isB
. 在執行時間,a
會先評估。At run-time,a
is first evaluated. 如果不a
是 null,a
則會將解除包裝為類型A0
(如果存在,而且可為A
null) 並且轉換為類型,則會B
變成結果。Ifa
is not null,a
is unwrapped to typeA0
(ifA
exists and is nullable) and converted to typeB
, and this becomes the result. 否則,b
會進行評估並成為結果。Otherwise,b
is evaluated and becomes the result. - 否則,
a
和b
不相容,而且會發生編譯時期錯誤。Otherwise,a
andb
are incompatible, and a compile-time error occurs.
條件運算子Conditional operator
?:
運算子稱為條件運算子。The ?:
operator is called the conditional operator. 它有時也稱為三元運算子。It is at times also called the ternary operator.
conditional_expression
: null_coalescing_expression
| null_coalescing_expression '?' expression ':' expression
;
表單的條件運算式會 b ? x : y
先評估條件 b
。A conditional expression of the form b ? x : y
first evaluates the condition b
. 然後,如果 b
是 true
, x
則會評估,並且成為作業的結果。Then, if b
is true
, x
is evaluated and becomes the result of the operation. 否則, y
會進行評估,並成為作業的結果。Otherwise, y
is evaluated and becomes the result of the operation. 條件運算式永遠不會評估 x
和 y
。A conditional expression never evaluates both x
and y
.
條件運算子是右向關聯的,表示作業是由右至左分組。The conditional operator is right-associative, meaning that operations are grouped from right to left. 例如,表單的運算式 a ? b : c ? d : e
會評估為 a ? b : (c ? d : e)
。For example, an expression of the form a ? b : c ? d : e
is evaluated as a ? b : (c ? d : e)
.
運算子的第一個運算元 ?:
必須是可以隱含地轉換為的運算式 bool
,或是實作為型別的運算式 operator true
。The first operand of the ?:
operator must be an expression that can be implicitly converted to bool
, or an expression of a type that implements operator true
. 如果未滿足上述任何一項需求,就會發生編譯時期錯誤。If neither of these requirements is satisfied, a compile-time error occurs.
運算子的第二個和第三個運算元 x
y
?:
控制條件運算式的型別。The second and third operands, x
and y
, of the ?:
operator control the type of the conditional expression.
- 如果
x
有型別X
,而且y
有型別Y
thenIfx
has typeX
andy
has typeY
then- 如果隱含轉換 (隱含 轉換) 存在於
X
至Y
,而不是從轉換為,則Y
X
Y
是條件運算式的類型。If an implicit conversion (Implicit conversions) exists fromX
toY
, but not fromY
toX
, thenY
is the type of the conditional expression. - 如果隱含轉換 (隱含 轉換) 存在於
Y
至X
,而不是從轉換為,則X
Y
X
是條件運算式的類型。If an implicit conversion (Implicit conversions) exists fromY
toX
, but not fromX
toY
, thenX
is the type of the conditional expression. - 否則,就不能判斷任何運算式型別,而且會發生編譯時期錯誤。Otherwise, no expression type can be determined, and a compile-time error occurs.
- 如果隱含轉換 (隱含 轉換) 存在於
- 如果只有一個
x
和y
具有型別,而且和兩者都可以隱含地x
y
轉換成該型別,則這是條件運算式的型別。If only one ofx
andy
has a type, and bothx
andy
, of are implicitly convertible to that type, then that is the type of the conditional expression. - 否則,就不能判斷任何運算式型別,而且會發生編譯時期錯誤。Otherwise, no expression type can be determined, and a compile-time error occurs.
表單之條件運算式的執行時間處理是 b ? x : y
由下列步驟所組成:The run-time processing of a conditional expression of the form b ? x : y
consists of the following steps:
- 首先,
b
會進行評估,並bool
決定的值b
:First,b
is evaluated, and thebool
value ofb
is determined:- 如果從的型別隱含轉換
b
bool
存在,則會執行這項隱含轉換來產生bool
值。If an implicit conversion from the type ofb
tobool
exists, then this implicit conversion is performed to produce abool
value. - 否則,會叫用的型別所
operator true
定義的b
來產生bool
值。Otherwise, theoperator true
defined by the type ofb
is invoked to produce abool
value.
- 如果從的型別隱含轉換
- 如果
bool
上述步驟所產生的值為true
,則x
會進行評估並轉換成條件運算式的類型,而這會成為條件運算式的結果。If thebool
value produced by the step above istrue
, thenx
is evaluated and converted to the type of the conditional expression, and this becomes the result of the conditional expression. - 否則,
y
會進行評估並轉換成條件運算式的類型,而這會成為條件運算式的結果。Otherwise,y
is evaluated and converted to the type of the conditional expression, and this becomes the result of the conditional expression.
匿名函式運算式Anonymous function expressions
匿名 函式是表示「內嵌」方法定義的運算式。An anonymous function is an expression that represents an "in-line" method definition. 匿名函式本身沒有值或型別,但是可以轉換成相容的委派或運算式樹狀架構型別。An anonymous function does not have a value or type in and of itself, but is convertible to a compatible delegate or expression tree type. 匿名函式轉換的評估取決於轉換的目標型別:如果它是委派型別,則轉換會評估為參考匿名函式所定義之方法的委派值。The evaluation of an anonymous function conversion depends on the target type of the conversion: If it is a delegate type, the conversion evaluates to a delegate value referencing the method which the anonymous function defines. 如果是運算式樹狀架構型別,則轉換會評估為運算式樹狀架構,它會將方法的結構表示為物件結構。If it is an expression tree type, the conversion evaluates to an expression tree which represents the structure of the method as an object structure.
基於歷史原因,匿名函式有兩種語法類別,也就是 lambda_expression s 和 anonymous_method_expression s。For historical reasons there are two syntactic flavors of anonymous functions, namely lambda_expression s and anonymous_method_expression s. 對於幾乎所有的目的而言, lambda_expression s 比 anonymous_method_expression 的更為精簡且易懂,後者仍會保留為回溯相容性的語言。For almost all purposes, lambda_expression s are more concise and expressive than anonymous_method_expression s, which remain in the language for backwards compatibility.
lambda_expression
: anonymous_function_signature '=>' anonymous_function_body
;
anonymous_method_expression
: 'delegate' explicit_anonymous_function_signature? block
;
anonymous_function_signature
: explicit_anonymous_function_signature
| implicit_anonymous_function_signature
;
explicit_anonymous_function_signature
: '(' explicit_anonymous_function_parameter_list? ')'
;
explicit_anonymous_function_parameter_list
: explicit_anonymous_function_parameter (',' explicit_anonymous_function_parameter)*
;
explicit_anonymous_function_parameter
: anonymous_function_parameter_modifier? type identifier
;
anonymous_function_parameter_modifier
: 'ref'
| 'out'
;
implicit_anonymous_function_signature
: '(' implicit_anonymous_function_parameter_list? ')'
| implicit_anonymous_function_parameter
;
implicit_anonymous_function_parameter_list
: implicit_anonymous_function_parameter (',' implicit_anonymous_function_parameter)*
;
implicit_anonymous_function_parameter
: identifier
;
anonymous_function_body
: expression
| block
;
=>
運算子的優先順序與指派 (=
) 相同,而且是右向關聯。The =>
operator has the same precedence as assignment (=
) and is right-associative.
具有修飾詞的匿名函式 async
是非同步函式,並遵循 非同步函式中所述的規則。An anonymous function with the async
modifier is an async function and follows the rules described in Async functions.
匿名函式的參數(以 lambda_expression 的形式)可以明確或隱含的型別。The parameters of an anonymous function in the form of a lambda_expression can be explicitly or implicitly typed. 在明確類型的參數清單中,會明確陳述每個參數的型別。In an explicitly typed parameter list, the type of each parameter is explicitly stated. 在隱含型別參數清單中,參數的型別是從發生匿名函式的內容推斷而來的,尤其是當匿名函式轉換成相容的委派型別或運算式樹狀架構型別時,該型別會提供參數類型 (匿名函式 轉換) 。In an implicitly typed parameter list, the types of the parameters are inferred from the context in which the anonymous function occurs—specifically, when the anonymous function is converted to a compatible delegate type or expression tree type, that type provides the parameter types (Anonymous function conversions).
在具有單一隱含類型參數的匿名函式中,可以省略參數清單中的括弧。In an anonymous function with a single, implicitly typed parameter, the parentheses may be omitted from the parameter list. 換句話說,這是表單的匿名函式In other words, an anonymous function of the form
( param ) => expr
可以縮寫為can be abbreviated to
param => expr
匿名函式的參數清單(以 anonymous_method_expression 的形式)是選擇性的。The parameter list of an anonymous function in the form of an anonymous_method_expression is optional. 如果有指定,則必須明確地輸入參數。If given, the parameters must be explicitly typed. 如果沒有,匿名函式可以轉換成具有任何參數清單(不含參數)的委派 out
。If not, the anonymous function is convertible to a delegate with any parameter list not containing out
parameters.
匿名函式的 區塊 主體可 (端點和 可存取性) 連接,除非匿名函式發生在無法連接的語句內。A block body of an anonymous function is reachable (End points and reachability) unless the anonymous function occurs inside an unreachable statement.
匿名函式的一些範例如下:Some examples of anonymous functions follow below:
x => x + 1 // Implicitly typed, expression body
x => { return x + 1; } // Implicitly typed, statement body
(int x) => x + 1 // Explicitly typed, expression body
(int x) => { return x + 1; } // Explicitly typed, statement body
(x, y) => x * y // Multiple parameters
() => Console.WriteLine() // No parameters
async (t1,t2) => await t1 + await t2 // Async
delegate (int x) { return x + 1; } // Anonymous method expression
delegate { return 1 + 1; } // Parameter list omitted
除了下列幾點之外, lambda_expression s 和 anonymous_method_expression s 的行為相同:The behavior of lambda_expression s and anonymous_method_expression s is the same except for the following points:
- anonymous_method_expression 允許完全省略參數清單,產生可轉換性來委派任何值參數清單的類型。anonymous_method_expression s permit the parameter list to be omitted entirely, yielding convertibility to delegate types of any list of value parameters.
- lambda_expression 允許省略和推斷參數類型,而 anonymous_method_expression s 則需要明確陳述參數類型。lambda_expression s permit parameter types to be omitted and inferred whereas anonymous_method_expression s require parameter types to be explicitly stated.
- Lambda_expression 的主體可以是運算式或語句區塊,而 anonymous_method_expression 的主體必須是語句區塊。The body of a lambda_expression can be an expression or a statement block whereas the body of an anonymous_method_expression must be a statement block.
- 只有 lambda_expression s 會轉換成相容的運算式樹狀架構類型 (運算式樹狀架構類型) 。Only lambda_expression s have conversions to compatible expression tree types (Expression tree types).
匿名函式簽章Anonymous function signatures
匿名函式的選擇性 anonymous_function_signature 定義匿名函式的名稱,以及選擇性的型式參數類型。The optional anonymous_function_signature of an anonymous function defines the names and optionally the types of the formal parameters for the anonymous function. 匿名函式的參數範圍是 anonymous_function_body。The scope of the parameters of the anonymous function is the anonymous_function_body. (範圍) 和參數清單 ((如果指定的話)) 匿名方法主體會構成宣告空間 (宣告) 。(Scopes) Together with the parameter list (if given) the anonymous-method-body constitutes a declaration space (Declarations). 因此,匿名函式之參數名稱的編譯時期錯誤,會比對其範圍包含 anonymous_method_expression 或 lambda_expression 的區域變數、本機常數或參數的名稱。It is thus a compile-time error for the name of a parameter of the anonymous function to match the name of a local variable, local constant or parameter whose scope includes the anonymous_method_expression or lambda_expression.
如果匿名函式有 explicit_anonymous_function_signature,則相容委派型別和運算式樹狀架構類型的集合,會限制為具有相同順序的相同參數類型和修飾詞。If an anonymous function has an explicit_anonymous_function_signature, then the set of compatible delegate types and expression tree types is restricted to those that have the same parameter types and modifiers in the same order. 相較于方法群組轉換 (方法群組轉換) ,不支援匿名函式參數類型的不變變異數。In contrast to method group conversions (Method group conversions), contra-variance of anonymous function parameter types is not supported. 如果匿名函式沒有 anonymous_function_signature,則會將一組相容的委派型別和運算式樹狀架構型別限制為沒有參數的類型 out
。If an anonymous function does not have an anonymous_function_signature, then the set of compatible delegate types and expression tree types is restricted to those that have no out
parameters.
請注意, anonymous_function_signature 不能包含屬性或參數陣列。Note that an anonymous_function_signature cannot include attributes or a parameter array. 然而, anonymous_function_signature 可能與參數清單包含參數陣列的委派型別相容。Nevertheless, an anonymous_function_signature may be compatible with a delegate type whose parameter list contains a parameter array.
另外也請注意,即使相容,轉換成運算式樹狀架構類型仍可能在編譯時期 (運算式樹狀結構類型) 時失敗。Note also that conversion to an expression tree type, even if compatible, may still fail at compile-time (Expression tree types).
匿名函數主體Anonymous function bodies
匿名函式 (運算式 或 區塊) 主體受限於下列規則:The body (expression or block) of an anonymous function is subject to the following rules:
- 如果匿名函式包含簽章,則簽章中指定的參數會出現在主體中。If the anonymous function includes a signature, the parameters specified in the signature are available in the body. 如果匿名函式沒有簽章,則可以將參數轉換成具有參數 (匿名函式 轉換) 的委派類型或運算式類型,但無法在主體中存取參數。If the anonymous function has no signature it can be converted to a delegate type or expression type having parameters (Anonymous function conversions), but the parameters cannot be accessed in the body.
- 除了簽
ref
章out
中指定的或參數 (如果最接近的封入匿名函式有任何) ,就會發生編譯時期錯誤,主體才可存取ref
或out
參數。Except forref
orout
parameters specified in the signature (if any) of the nearest enclosing anonymous function, it is a compile-time error for the body to access aref
orout
parameter. - 當的型別
this
是結構類型時,就是要存取主體的編譯時期錯誤this
。When the type ofthis
is a struct type, it is a compile-time error for the body to accessthis
. 無論存取是否明確 (如this.x
) 或隱含 (一樣,例如x
wherex
是結構) 的實例成員。This is true whether the access is explicit (as inthis.x
) or implicit (as inx
wherex
is an instance member of the struct). 此規則只會禁止這類存取,而且不會影響成員查閱結果是否在結構的成員中。This rule simply prohibits such access and does not affect whether member lookup results in a member of the struct. - 主體可存取匿名函式 (外部 變數) 外部變數。The body has access to the outer variables (Outer variables) of the anonymous function. 外部變數的存取權將會參考 lambda_expression 或 anonymous_method_expression (評估時使用中的變數實例,) 匿名函數運算式的評估 。Access of an outer variable will reference the instance of the variable that is active at the time the lambda_expression or anonymous_method_expression is evaluated (Evaluation of anonymous function expressions).
- 這是一個編譯時期錯誤,主體包含的
goto
語句、break
語句或continue
語句的目標是在主體外部,或在包含的匿名函式主體內。It is a compile-time error for the body to contain agoto
statement,break
statement, orcontinue
statement whose target is outside the body or within the body of a contained anonymous function. return
主體中的語句會從最接近的封入匿名函式的調用傳回控制權,而不是從封入函數成員傳回。Areturn
statement in the body returns control from an invocation of the nearest enclosing anonymous function, not from the enclosing function member. 語句中指定的運算式return
必須可以隱含地轉換成委派型別或運算式樹狀結構型別的傳回型別,也就是最接近的封入 lambda_expression 或 anonymous_method_expression 轉換 (匿名函數轉換) 。An expression specified in areturn
statement must be implicitly convertible to the return type of the delegate type or expression tree type to which the nearest enclosing lambda_expression or anonymous_method_expression is converted (Anonymous function conversions).
無論是否有任何方法可以執行匿名函式的區塊,而不是透過 lambda_expression 或 anonymous_method_expression 的評估和調用,也會明確指定。It is explicitly unspecified whether there is any way to execute the block of an anonymous function other than through evaluation and invocation of the lambda_expression or anonymous_method_expression. 尤其是,編譯器可能會選擇藉由合成一或多個命名方法或類型來執行匿名函式。In particular, the compiler may choose to implement an anonymous function by synthesizing one or more named methods or types. 任何這類合成元素的名稱都必須是保留供編譯器使用的表單。The names of any such synthesized elements must be of a form reserved for compiler use.
多載解析和匿名函數Overload resolution and anonymous functions
引數清單中的匿名函式會參與型別推斷及多載解析。Anonymous functions in an argument list participate in type inference and overload resolution. 請參閱確切規則的 型別推斷 和多載 解析 。Please refer to Type inference and Overload resolution for the exact rules.
下列範例說明匿名函式對多載解析的影響。The following example illustrates the effect of anonymous functions on overload resolution.
class ItemList<T>: List<T>
{
public int Sum(Func<T,int> selector) {
int sum = 0;
foreach (T item in this) sum += selector(item);
return sum;
}
public double Sum(Func<T,double> selector) {
double sum = 0;
foreach (T item in this) sum += selector(item);
return sum;
}
}
ItemList<T>
類別有兩種 Sum
方法。The ItemList<T>
class has two Sum
methods. 每個都採用 selector
引數,它會從清單專案中解壓縮值以加總。Each takes a selector
argument, which extracts the value to sum over from a list item. 解壓縮的值可以是 int
或 double
,而且產生的總和同樣是 int
或 double
。The extracted value can be either an int
or a double
and the resulting sum is likewise either an int
or a double
.
例如,您 Sum
可以使用方法,根據訂單中的詳細資料行清單來計算總和。The Sum
methods could for example be used to compute sums from a list of detail lines in an order.
class Detail
{
public int UnitCount;
public double UnitPrice;
...
}
void ComputeSums() {
ItemList<Detail> orderDetails = GetOrderDetails(...);
int totalUnits = orderDetails.Sum(d => d.UnitCount);
double orderTotal = orderDetails.Sum(d => d.UnitPrice * d.UnitCount);
...
}
在的第一個調用中 orderDetails.Sum
,這兩種 Sum
方法都適用,因為匿名函式 d => d. UnitCount
與和都相容 Func<Detail,int>
Func<Detail,double>
。In the first invocation of orderDetails.Sum
, both Sum
methods are applicable because the anonymous function d => d. UnitCount
is compatible with both Func<Detail,int>
and Func<Detail,double>
. 不過,多載解析會挑選第一個 Sum
方法,因為轉換成 Func<Detail,int>
優於轉換成 Func<Detail,double>
。However, overload resolution picks the first Sum
method because the conversion to Func<Detail,int>
is better than the conversion to Func<Detail,double>
.
在的第二個調用中 orderDetails.Sum
,只有第二個 Sum
方法適用,因為匿名函式會 d => d.UnitPrice * d.UnitCount
產生類型的值 double
。In the second invocation of orderDetails.Sum
, only the second Sum
method is applicable because the anonymous function d => d.UnitPrice * d.UnitCount
produces a value of type double
. 因此,多載解析會挑選該調用的第二個 Sum
方法。Thus, overload resolution picks the second Sum
method for that invocation.
匿名函式和動態繫結Anonymous functions and dynamic binding
匿名函式不可以是動態繫結作業的接收者、引數或運算元。An anonymous function cannot be a receiver, argument or operand of a dynamically bound operation.
外部變數Outer variables
任何區域變數、值參數或其範圍包含 lambda_expression 或 anonymous_method_expression 的參數陣列,稱為匿名函式的 外部變數 。Any local variable, value parameter, or parameter array whose scope includes the lambda_expression or anonymous_method_expression is called an outer variable of the anonymous function. 在類別的實例函式成員中, this
值會被視為值參數,而且是包含在函數成員內之任何匿名函式的外部變數。In an instance function member of a class, the this
value is considered a value parameter and is an outer variable of any anonymous function contained within the function member.
已捕捉的外部變數Captured outer variables
匿名函式參考外部變數時,會將外部變數稱為匿名函式所 捕捉 。When an outer variable is referenced by an anonymous function, the outer variable is said to have been captured by the anonymous function. 一般來說,本機變數的存留期僅限於執行與 (區域變數) 相關聯的區塊或語句。Ordinarily, the lifetime of a local variable is limited to execution of the block or statement with which it is associated (Local variables). 不過,在從匿名函式建立的委派或運算式樹狀結構變成適合進行垃圾收集之前,已捕捉的外部變數存留期至少會延伸。However, the lifetime of a captured outer variable is extended at least until the delegate or expression tree created from the anonymous function becomes eligible for garbage collection.
在範例中In the example
using System;
delegate int D();
class Test
{
static D F() {
int x = 0;
D result = () => ++x;
return result;
}
static void Main() {
D d = F();
Console.WriteLine(d());
Console.WriteLine(d());
Console.WriteLine(d());
}
}
區域變數 x
是由匿名函式所捕捉,而且的存留期 x
至少要等到從傳回的委派 F
變成合格的垃圾收集 (才會發生,直到程式的最後面) 為止。the local variable x
is captured by the anonymous function, and the lifetime of x
is extended at least until the delegate returned from F
becomes eligible for garbage collection (which doesn't happen until the very end of the program). 由於匿名函式的每個調用都是在相同的實例上運作 x
,因此範例的輸出為:Since each invocation of the anonymous function operates on the same instance of x
, the output of the example is:
1
2
3
匿名函式捕捉到區域變數或值參數時,就不會再將區域變數或參數視為固定變數 (固定和可移動變數) ,但會被視為可移動變數。When a local variable or a value parameter is captured by an anonymous function, the local variable or parameter is no longer considered to be a fixed variable (Fixed and moveable variables), but is instead considered to be a moveable variable. 因此 unsafe
,任何採用已捕捉外部變數位址的程式碼,都必須先使用 fixed
語句來修正變數。Thus any unsafe
code that takes the address of a captured outer variable must first use the fixed
statement to fix the variable.
請注意,不同于 uncaptured 變數,已捕捉的區域變數可以同時公開給多個執行執行緒。Note that unlike an uncaptured variable, a captured local variable can be simultaneously exposed to multiple threads of execution.
區域變數的具現化Instantiation of local variables
當執行進入變數的範圍時,就會將本機變數視為具現 化 。A local variable is considered to be instantiated when execution enters the scope of the variable. 例如,叫用下列方法時,會將區域變數 x
具現化並初始化三次,每次反覆運算迴圈。For example, when the following method is invoked, the local variable x
is instantiated and initialized three times—once for each iteration of the loop.
static void F() {
for (int i = 0; i < 3; i++) {
int x = i * 2 + 1;
...
}
}
不過,移動迴圈外的宣告會產生的單一具現 x
化 x
:However, moving the declaration of x
outside the loop results in a single instantiation of x
:
static void F() {
int x;
for (int i = 0; i < 3; i++) {
x = i * 2 + 1;
...
}
}
如果未捕獲,就無法確切觀察區域變數的具現化頻率(因為具現化的存留期不相鄰),因此每個具現化都可能只使用相同的儲存位置。When not captured, there is no way to observe exactly how often a local variable is instantiated—because the lifetimes of the instantiations are disjoint, it is possible for each instantiation to simply use the same storage location. 不過,當匿名函式捕捉到區域變數時,具現化的效果會變得很明顯。However, when an anonymous function captures a local variable, the effects of instantiation become apparent.
範例The example
using System;
delegate void D();
class Test
{
static D[] F() {
D[] result = new D[3];
for (int i = 0; i < 3; i++) {
int x = i * 2 + 1;
result[i] = () => { Console.WriteLine(x); };
}
return result;
}
static void Main() {
foreach (D d in F()) d();
}
}
產生下列輸出:produces the output:
1
3
5
但是,當的宣告 x
移至迴圈外時:However, when the declaration of x
is moved outside the loop:
static D[] F() {
D[] result = new D[3];
int x;
for (int i = 0; i < 3; i++) {
x = i * 2 + 1;
result[i] = () => { Console.WriteLine(x); };
}
return result;
}
輸出為:the output is:
5
5
5
如果 for 迴圈宣告了反覆運算變數,則會將該變數本身視為在迴圈外部宣告。If a for-loop declares an iteration variable, that variable itself is considered to be declared outside of the loop. 因此,如果範例變更為捕捉反覆運算變數本身:Thus, if the example is changed to capture the iteration variable itself:
static D[] F() {
D[] result = new D[3];
for (int i = 0; i < 3; i++) {
result[i] = () => { Console.WriteLine(i); };
}
return result;
}
只會捕獲一個反覆運算變數的實例,這會產生輸出:only one instance of the iteration variable is captured, which produces the output:
3
3
3
匿名函式委派有可能共用部分已捕捉的變數,但有不同的其他實例。It is possible for anonymous function delegates to share some captured variables yet have separate instances of others. 例如,如果 F
變更為For example, if F
is changed to
static D[] F() {
D[] result = new D[3];
int x = 0;
for (int i = 0; i < 3; i++) {
int y = 0;
result[i] = () => { Console.WriteLine("{0} {1}", ++x, ++y); };
}
return result;
}
這三個委派會捕捉相同的實例 x
,但不同的實例 y
,輸出為:the three delegates capture the same instance of x
but separate instances of y
, and the output is:
1 1
2 1
3 1
不同的匿名函式可以捕獲外部變數的相同實例。Separate anonymous functions can capture the same instance of an outer variable. 在範例中︰In the example:
using System;
delegate void Setter(int value);
delegate int Getter();
class Test
{
static void Main() {
int x = 0;
Setter s = (int value) => { x = value; };
Getter g = () => { return x; };
s(5);
Console.WriteLine(g());
s(10);
Console.WriteLine(g());
}
}
這兩個匿名函式會捕捉相同的本機變數實例 x
,因此可以透過該變數「通訊」。the two anonymous functions capture the same instance of the local variable x
, and they can thus "communicate" through that variable. 範例的輸出如下:The output of the example is:
5
10
匿名函式運算式的評估Evaluation of anonymous function expressions
匿名函式 F
必須一律轉換成委派類型 D
或運算式樹狀結構類型 E
,不論是直接或透過執行委派建立運算式 new D(F)
。An anonymous function F
must always be converted to a delegate type D
or an expression tree type E
, either directly or through the execution of a delegate creation expression new D(F)
. 這項轉換會決定匿名函式的結果,如 匿名函數轉換中所述。This conversion determines the result of the anonymous function, as described in Anonymous function conversions.
查詢運算式Query expressions
查詢運算式 會針對類似關聯式和階層式查詢語言的查詢(例如 SQL 和 XQuery)提供語言整合語法。Query expressions provide a language integrated syntax for queries that is similar to relational and hierarchical query languages such as SQL and XQuery.
query_expression
: from_clause query_body
;
from_clause
: 'from' type? identifier 'in' expression
;
query_body
: query_body_clauses? select_or_group_clause query_continuation?
;
query_body_clauses
: query_body_clause
| query_body_clauses query_body_clause
;
query_body_clause
: from_clause
| let_clause
| where_clause
| join_clause
| join_into_clause
| orderby_clause
;
let_clause
: 'let' identifier '=' expression
;
where_clause
: 'where' boolean_expression
;
join_clause
: 'join' type? identifier 'in' expression 'on' expression 'equals' expression
;
join_into_clause
: 'join' type? identifier 'in' expression 'on' expression 'equals' expression 'into' identifier
;
orderby_clause
: 'orderby' orderings
;
orderings
: ordering (',' ordering)*
;
ordering
: expression ordering_direction?
;
ordering_direction
: 'ascending'
| 'descending'
;
select_or_group_clause
: select_clause
| group_clause
;
select_clause
: 'select' expression
;
group_clause
: 'group' expression 'by' expression
;
query_continuation
: 'into' identifier query_body
;
查詢運算式是以子句開頭 from
,並以 select
or group
子句結尾。A query expression begins with a from
clause and ends with either a select
or group
clause. 初始 from
子句後面可以是零或多個 from
、 let
、 where
join
或 orderby
子句。The initial from
clause can be followed by zero or more from
, let
, where
, join
or orderby
clauses. 每個 from
子句都是引入 *範圍變數 _ 的產生器,其範圍是 _ sequence * 的元素。Each from
clause is a generator introducing a range variable _ which ranges over the elements of a _sequence**. 每個子句都會導入 let
一個範圍變數,代表以先前的範圍變數所計算的值。Each let
clause introduces a range variable representing a value computed by means of previous range variables. 每個 where
子句都是從結果中排除專案的篩選準則。Each where
clause is a filter that excludes items from the result. 每個 join
子句都會比較來源序列的指定索引鍵與另一個序列的索引鍵,以產生相符的配對。Each join
clause compares specified keys of the source sequence with keys of another sequence, yielding matching pairs. 每個 orderby
子句會根據指定的準則重新排序專案。Final select
或 group
子句會根據範圍變數來指定結果的形狀。Each orderby
clause reorders items according to specified criteria.The final select
or group
clause specifies the shape of the result in terms of the range variables. 最後, into
子句可以用來「拼接」查詢,方法是將某個查詢的結果視為後續查詢中的產生器。Finally, an into
clause can be used to "splice" queries by treating the results of one query as a generator in a subsequent query.
查詢運算式中的多義性Ambiguities in query expressions
查詢運算式包含許多「內容關鍵字」,也就是在給定內容中具有特殊意義的識別碼。Query expressions contain a number of "contextual keywords", i.e., identifiers that have special meaning in a given context. 具體而言,就是、、、、、、、、、、 from
where
join
on
equals
into
let
orderby
ascending
descending
select
group
和 by
。Specifically these are from
, where
, join
, on
, equals
, into
, let
, orderby
, ascending
, descending
, select
, group
and by
. 為了避免由於將這些識別碼混用為關鍵字或簡單名稱而造成的查詢運算式不明確,在查詢運算式中的任何位置進行這些識別碼時,這些識別碼都會被視為關鍵字。In order to avoid ambiguities in query expressions caused by mixed use of these identifiers as keywords or simple names, these identifiers are considered keywords when occurring anywhere within a query expression.
基於這個目的,查詢運算式是以 " from identifier
" 後面接著任何標記("" ;
," =
" 或 "" 除外)開頭的任何運算式 ,
。For this purpose, a query expression is any expression that starts with "from identifier
" followed by any token except ";
", "=
" or ",
".
若要在查詢運算式中使用這些字組作為識別碼,可以在前面加上 " @
" (識別碼) 。In order to use these words as identifiers within a query expression, they can be prefixed with "@
" (Identifiers).
查詢運算式轉譯Query expression translation
C # 語言不會指定查詢運算式的執行語法。The C# language does not specify the execution semantics of query expressions. 相反地,查詢運算式會轉譯成符合 查詢運算式模式 的方法調用, (查詢運算式模式) 。Rather, query expressions are translated into invocations of methods that adhere to the query expression pattern (The query expression pattern). 具體而言,查詢運算式會轉譯為名為 Where
、、 Select
SelectMany
、 Join
、 GroupJoin
OrderBy
OrderByDescending
ThenBy
ThenByDescending
GroupBy
Cast
、、、、、和的方法調用。這些方法預期會有特定的簽章和結果類型,如 查詢運算式模式中所述。Specifically, query expressions are translated into invocations of methods named Where
, Select
, SelectMany
, Join
, GroupJoin
, OrderBy
, OrderByDescending
, ThenBy
, ThenByDescending
, GroupBy
, and Cast
.These methods are expected to have particular signatures and result types, as described in The query expression pattern. 這些方法可以是所查詢之物件的實例方法或物件外部的擴充方法,而且它們會執行查詢的實際執行。These methods can be instance methods of the object being queried or extension methods that are external to the object, and they implement the actual execution of the query.
從查詢運算式到方法調用的轉譯是在執行任何類型系結或多載解析之前發生的語法對應。The translation from query expressions to method invocations is a syntactic mapping that occurs before any type binding or overload resolution has been performed. 轉譯保證語法正確,但不保證會產生語義正確的 c # 程式碼。The translation is guaranteed to be syntactically correct, but it is not guaranteed to produce semantically correct C# code. 在查詢運算式的轉譯之後,會將產生的方法叫用視為一般方法調用來處理,而這可能會導致發現錯誤,例如,如果方法不存在、引數有錯誤的型別,或者方法是泛型,且型別推斷失敗。Following translation of query expressions, the resulting method invocations are processed as regular method invocations, and this may in turn uncover errors, for example if the methods do not exist, if arguments have wrong types, or if the methods are generic and type inference fails.
藉由重複套用下列轉譯來處理查詢運算式,直到無法進一步降低。A query expression is processed by repeatedly applying the following translations until no further reductions are possible. 轉譯會依應用程式順序列出:每一節假設先前章節中的翻譯都已徹底執行,一旦完成後,就不會在處理相同的查詢運算式時,再進行一次。The translations are listed in order of application: each section assumes that the translations in the preceding sections have been performed exhaustively, and once exhausted, a section will not later be revisited in the processing of the same query expression.
查詢運算式中不允許指派給範圍變數。Assignment to range variables is not allowed in query expressions. 不過,c # 的執行不一定會強制執行這項限制,因為這裡所提供的語法轉譯配置有時可能無法這麼做。However a C# implementation is permitted to not always enforce this restriction, since this may sometimes not be possible with the syntactic translation scheme presented here.
某些翻譯插入範圍變數,並以表示的透明識別碼表示 *
。Certain translations inject range variables with transparent identifiers denoted by *
. 透明識別碼的特殊屬性會在 透明識別碼中進一步討論。The special properties of transparent identifiers are discussed further in Transparent identifiers.
具有接續的 Select 和 groupby 子句Select and groupby clauses with continuations
具有接續的查詢運算式A query expression with a continuation
from ... into x ...
會轉譯成is translated into
from x in ( from ... ) ...
下列各節中的翻譯假設查詢沒有接續 into
。The translations in the following sections assume that queries have no into
continuations.
範例The example
from c in customers
group c by c.Country into g
select new { Country = g.Key, CustCount = g.Count() }
會轉譯成is translated into
from g in
from c in customers
group c by c.Country
select new { Country = g.Key, CustCount = g.Count() }
最終的翻譯是the final translation of which is
customers.
GroupBy(c => c.Country).
Select(g => new { Country = g.Key, CustCount = g.Count() })
明確範圍變數類型Explicit range variable types
from
明確指定範圍變數類型的子句。A from
clause that explicitly specifies a range variable type
from T x in e
會轉譯成is translated into
from x in ( e ) . Cast < T > ( )
join
明確指定範圍變數類型的子句。A join
clause that explicitly specifies a range variable type
join T x in e on k1 equals k2
會轉譯成is translated into
join x in ( e ) . Cast < T > ( ) on k1 equals k2
下列各節中的翻譯假設查詢沒有明確的範圍變數類型。The translations in the following sections assume that queries have no explicit range variable types.
範例The example
from Customer c in customers
where c.City == "London"
select c
會轉譯成is translated into
from c in customers.Cast<Customer>()
where c.City == "London"
select c
最終的翻譯是the final translation of which is
customers.
Cast<Customer>().
Where(c => c.City == "London")
明確範圍變數型別有助於查詢實作為非泛型介面的集合 IEnumerable
,而不是泛型 IEnumerable<T>
介面。Explicit range variable types are useful for querying collections that implement the non-generic IEnumerable
interface, but not the generic IEnumerable<T>
interface. 在上述範例中,如果的型別為,就會發生這種情況 customers
ArrayList
。In the example above, this would be the case if customers
were of type ArrayList
.
退化查詢運算式Degenerate query expressions
表單的查詢運算式A query expression of the form
from x in e select x
會轉譯成is translated into
( e ) . Select ( x => x )
範例The example
from c in customers
select c
會轉譯成is translated into
customers.Select(c => c)
退化查詢運算式是完整選取來源元素的運算式。A degenerate query expression is one that trivially selects the elements of the source. 轉譯的後續階段會移除其他轉譯步驟所引進的退化查詢,方法是將它們取代為其來源。A later phase of the translation removes degenerate queries introduced by other translation steps by replacing them with their source. 不過,請務必確定查詢運算式的結果永遠不是來源物件本身,因為這樣會顯示查詢用戶端的來源型別和身分識別。It is important however to ensure that the result of a query expression is never the source object itself, as that would reveal the type and identity of the source to the client of the query. 因此,此步驟會在來源上明確呼叫,以保護直接在原始程式碼中撰寫的退化查詢 Select
。Therefore this step protects degenerate queries written directly in source code by explicitly calling Select
on the source. 然後由 Select
和其他查詢運算子的實作者來確保這些方法永遠不會傳回來源物件本身。It is then up to the implementers of Select
and other query operators to ensure that these methods never return the source object itself.
From、let、where、join 和 orderby 子句From, let, where, join and orderby clauses
具有第二個 from
子句後面接著子句的查詢 select
運算式A query expression with a second from
clause followed by a select
clause
from x1 in e1
from x2 in e2
select v
會轉譯成is translated into
( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => v )
具有第二個子句的查詢運算式,後面接著子句以外的某個部分 from
select
:A query expression with a second from
clause followed by something other than a select
clause:
from x1 in e1
from x2 in e2
...
會轉譯成is translated into
from * in ( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => new { x1 , x2 } )
...
具有子句的查詢運算式 let
A query expression with a let
clause
from x in e
let y = f
...
會轉譯成is translated into
from * in ( e ) . Select ( x => new { x , y = f } )
...
具有子句的查詢運算式 where
A query expression with a where
clause
from x in e
where f
...
會轉譯成is translated into
from x in ( e ) . Where ( x => f )
...
具有 join
子句且 into
後面沒有 select
子句的查詢運算式A query expression with a join
clause without an into
followed by a select
clause
from x1 in e1
join x2 in e2 on k1 equals k2
select v
會轉譯成is translated into
( e1 ) . Join( e2 , x1 => k1 , x2 => k2 , ( x1 , x2 ) => v )
具有子句的查詢運算式, join
但後面沒有子句以外的 into
其他內容 select
A query expression with a join
clause without an into
followed by something other than a select
clause
from x1 in e1
join x2 in e2 on k1 equals k2
...
會轉譯成is translated into
from * in ( e1 ) . Join( e2 , x1 => k1 , x2 => k2 , ( x1 , x2 ) => new { x1 , x2 })
...
具有 join
子句 into
後面接著 select
子句的查詢運算式A query expression with a join
clause with an into
followed by a select
clause
from x1 in e1
join x2 in e2 on k1 equals k2 into g
select v
會轉譯成is translated into
( e1 ) . GroupJoin( e2 , x1 => k1 , x2 => k2 , ( x1 , g ) => v )
具有子句的查詢運算式, join
into
後面接著子句以外的其他內容 select
A query expression with a join
clause with an into
followed by something other than a select
clause
from x1 in e1
join x2 in e2 on k1 equals k2 into g
...
會轉譯成is translated into
from * in ( e1 ) . GroupJoin( e2 , x1 => k1 , x2 => k2 , ( x1 , g ) => new { x1 , g })
...
具有子句的查詢運算式 orderby
A query expression with an orderby
clause
from x in e
orderby k1 , k2 , ..., kn
...
會轉譯成is translated into
from x in ( e ) .
OrderBy ( x => k1 ) .
ThenBy ( x => k2 ) .
... .
ThenBy ( x => kn )
...
如果順序子句指定 descending
方向指標,則 OrderByDescending
ThenByDescending
會改為產生或的調用。If an ordering clause specifies a descending
direction indicator, an invocation of OrderByDescending
or ThenByDescending
is produced instead.
下列轉譯假設沒有 let
、 where
join
或 orderby
子句,而且 from
每個查詢運算式中不能有一個以上的初始子句。The following translations assume that there are no let
, where
, join
or orderby
clauses, and no more than the one initial from
clause in each query expression.
範例The example
from c in customers
from o in c.Orders
select new { c.Name, o.OrderID, o.Total }
會轉譯成is translated into
customers.
SelectMany(c => c.Orders,
(c,o) => new { c.Name, o.OrderID, o.Total }
)
範例The example
from c in customers
from o in c.Orders
orderby o.Total descending
select new { c.Name, o.OrderID, o.Total }
會轉譯成is translated into
from * in customers.
SelectMany(c => c.Orders, (c,o) => new { c, o })
orderby o.Total descending
select new { c.Name, o.OrderID, o.Total }
最終的翻譯是the final translation of which is
customers.
SelectMany(c => c.Orders, (c,o) => new { c, o }).
OrderByDescending(x => x.o.Total).
Select(x => new { x.c.Name, x.o.OrderID, x.o.Total })
其中 x
是編譯器產生的識別碼,否則不可見和無法存取。where x
is a compiler generated identifier that is otherwise invisible and inaccessible.
範例The example
from o in orders
let t = o.Details.Sum(d => d.UnitPrice * d.Quantity)
where t >= 1000
select new { o.OrderID, Total = t }
會轉譯成is translated into
from * in orders.
Select(o => new { o, t = o.Details.Sum(d => d.UnitPrice * d.Quantity) })
where t >= 1000
select new { o.OrderID, Total = t }
最終的翻譯是the final translation of which is
orders.
Select(o => new { o, t = o.Details.Sum(d => d.UnitPrice * d.Quantity) }).
Where(x => x.t >= 1000).
Select(x => new { x.o.OrderID, Total = x.t })
其中 x
是編譯器產生的識別碼,否則不可見和無法存取。where x
is a compiler generated identifier that is otherwise invisible and inaccessible.
範例The example
from c in customers
join o in orders on c.CustomerID equals o.CustomerID
select new { c.Name, o.OrderDate, o.Total }
會轉譯成is translated into
customers.Join(orders, c => c.CustomerID, o => o.CustomerID,
(c, o) => new { c.Name, o.OrderDate, o.Total })
範例The example
from c in customers
join o in orders on c.CustomerID equals o.CustomerID into co
let n = co.Count()
where n >= 10
select new { c.Name, OrderCount = n }
會轉譯成is translated into
from * in customers.
GroupJoin(orders, c => c.CustomerID, o => o.CustomerID,
(c, co) => new { c, co })
let n = co.Count()
where n >= 10
select new { c.Name, OrderCount = n }
最終的翻譯是the final translation of which is
customers.
GroupJoin(orders, c => c.CustomerID, o => o.CustomerID,
(c, co) => new { c, co }).
Select(x => new { x, n = x.co.Count() }).
Where(y => y.n >= 10).
Select(y => new { y.x.c.Name, OrderCount = y.n)
其中 x
和 y
是編譯器產生的識別碼,在其他情況下不可見和無法存取。where x
and y
are compiler generated identifiers that are otherwise invisible and inaccessible.
範例The example
from o in orders
orderby o.Customer.Name, o.Total descending
select o
具有最終翻譯has the final translation
orders.
OrderBy(o => o.Customer.Name).
ThenByDescending(o => o.Total)
Select 子句Select clauses
表單的查詢運算式A query expression of the form
from x in e select v
會轉譯成is translated into
( e ) . Select ( x => v )
除非 v 是識別碼 x,否則翻譯只是except when v is the identifier x, the translation is simply
( e )
例如:For example
from c in customers.Where(c => c.City == "London")
select c
只會轉譯成is simply translated into
customers.Where(c => c.City == "London")
Groupby 子句Groupby clauses
表單的查詢運算式A query expression of the form
from x in e group v by k
會轉譯成is translated into
( e ) . GroupBy ( x => k , x => v )
除非 v 是識別碼 x,否則翻譯為except when v is the identifier x, the translation is
( e ) . GroupBy ( x => k )
範例The example
from c in customers
group c.Name by c.Country
會轉譯成is translated into
customers.
GroupBy(c => c.Country, c => c.Name)
透明識別碼Transparent identifiers
某些翻譯插入範圍變數,其中包含由表示的 *透明識別碼 _ _
。Certain translations inject range variables with *transparent identifiers _ denoted by _
. 透明識別碼不是正確的語言功能;它們只會以中繼步驟的形式存在於查詢運算式轉譯流程中。Transparent identifiers are not a proper language feature; they exist only as an intermediate step in the query expression translation process.
當查詢轉譯插入透明識別碼時,進一步的轉譯步驟會將透明識別碼傳播至匿名函式和匿名物件初始化運算式。When a query translation injects a transparent identifier, further translation steps propagate the transparent identifier into anonymous functions and anonymous object initializers. 在這些內容中,透明識別碼具有下列行為:In those contexts, transparent identifiers have the following behavior:
- 當透明識別碼以匿名函式中的參數形式出現時,關聯匿名型別的成員會自動在匿名函數主體的範圍內。When a transparent identifier occurs as a parameter in an anonymous function, the members of the associated anonymous type are automatically in scope in the body of the anonymous function.
- 當具有透明識別碼的成員在範圍內時,該成員的成員也會在範圍中。When a member with a transparent identifier is in scope, the members of that member are in scope as well.
- 當透明識別碼以匿名物件初始化運算式中的成員宣告子形式出現時,會引入具有透明識別碼的成員。When a transparent identifier occurs as a member declarator in an anonymous object initializer, it introduces a member with a transparent identifier.
- 在上述的轉譯步驟中,透明的識別碼一律會與匿名型別一起導入,而意圖是將多個範圍變數當作單一物件的成員來捕捉。In the translation steps described above, transparent identifiers are always introduced together with anonymous types, with the intent of capturing multiple range variables as members of a single object. C # 的執行允許使用與匿名型別不同的機制,將多個範圍變數群組在一起。An implementation of C# is permitted to use a different mechanism than anonymous types to group together multiple range variables. 下列轉譯範例假設使用匿名型別,並顯示透明識別碼如何轉譯。The following translation examples assume that anonymous types are used, and show how transparent identifiers can be translated away.
範例The example
from c in customers
from o in c.Orders
orderby o.Total descending
select new { c.Name, o.Total }
會轉譯成is translated into
from * in customers.
SelectMany(c => c.Orders, (c,o) => new { c, o })
orderby o.Total descending
select new { c.Name, o.Total }
這會進一步轉譯為which is further translated into
customers.
SelectMany(c => c.Orders, (c,o) => new { c, o }).
OrderByDescending(* => o.Total).
Select(* => new { c.Name, o.Total })
當您清除透明識別碼時,就相當於which, when transparent identifiers are erased, is equivalent to
customers.
SelectMany(c => c.Orders, (c,o) => new { c, o }).
OrderByDescending(x => x.o.Total).
Select(x => new { x.c.Name, x.o.Total })
其中 x
是編譯器產生的識別碼,否則不可見和無法存取。where x
is a compiler generated identifier that is otherwise invisible and inaccessible.
範例The example
from c in customers
join o in orders on c.CustomerID equals o.CustomerID
join d in details on o.OrderID equals d.OrderID
join p in products on d.ProductID equals p.ProductID
select new { c.Name, o.OrderDate, p.ProductName }
會轉譯成is translated into
from * in customers.
Join(orders, c => c.CustomerID, o => o.CustomerID,
(c, o) => new { c, o })
join d in details on o.OrderID equals d.OrderID
join p in products on d.ProductID equals p.ProductID
select new { c.Name, o.OrderDate, p.ProductName }
這會進一步縮減為which is further reduced to
customers.
Join(orders, c => c.CustomerID, o => o.CustomerID, (c, o) => new { c, o }).
Join(details, * => o.OrderID, d => d.OrderID, (*, d) => new { *, d }).
Join(products, * => d.ProductID, p => p.ProductID, (*, p) => new { *, p }).
Select(* => new { c.Name, o.OrderDate, p.ProductName })
最終的翻譯是the final translation of which is
customers.
Join(orders, c => c.CustomerID, o => o.CustomerID,
(c, o) => new { c, o }).
Join(details, x => x.o.OrderID, d => d.OrderID,
(x, d) => new { x, d }).
Join(products, y => y.d.ProductID, p => p.ProductID,
(y, p) => new { y, p }).
Select(z => new { z.y.x.c.Name, z.y.x.o.OrderDate, z.p.ProductName })
其中 x
、 y
和 z
是編譯器產生的識別碼,在其他情況下不可見且無法存取。where x
, y
, and z
are compiler generated identifiers that are otherwise invisible and inaccessible.
查詢運算式模式The query expression pattern
查詢運算式模式 會建立方法的模式,這些方法可供型別執行以支援查詢運算式。The Query expression pattern establishes a pattern of methods that types can implement to support query expressions. 由於查詢運算式會藉由語法對應轉譯為方法調用,因此類型在實作為查詢運算式模式的方式上具有相當大的彈性。Because query expressions are translated to method invocations by means of a syntactic mapping, types have considerable flexibility in how they implement the query expression pattern. 例如,模式的方法可以實作為實例方法或擴充方法,因為這兩個具有相同的調用語法,而且方法可以要求委派或運算式樹狀架構,因為匿名函式可以轉換為兩者。For example, the methods of the pattern can be implemented as instance methods or as extension methods because the two have the same invocation syntax, and the methods can request delegates or expression trees because anonymous functions are convertible to both.
支援查詢運算式模式之泛型型別的建議圖形 C<T>
如下所示。The recommended shape of a generic type C<T>
that supports the query expression pattern is shown below. 泛型型別是用來說明參數和結果型別之間的正確關聯性,但是也可以針對非泛型型別執行模式。A generic type is used in order to illustrate the proper relationships between parameter and result types, but it is possible to implement the pattern for non-generic types as well.
delegate R Func<T1,R>(T1 arg1);
delegate R Func<T1,T2,R>(T1 arg1, T2 arg2);
class C
{
public C<T> Cast<T>();
}
class C<T> : C
{
public C<T> Where(Func<T,bool> predicate);
public C<U> Select<U>(Func<T,U> selector);
public C<V> SelectMany<U,V>(Func<T,C<U>> selector,
Func<T,U,V> resultSelector);
public C<V> Join<U,K,V>(C<U> inner, Func<T,K> outerKeySelector,
Func<U,K> innerKeySelector, Func<T,U,V> resultSelector);
public C<V> GroupJoin<U,K,V>(C<U> inner, Func<T,K> outerKeySelector,
Func<U,K> innerKeySelector, Func<T,C<U>,V> resultSelector);
public O<T> OrderBy<K>(Func<T,K> keySelector);
public O<T> OrderByDescending<K>(Func<T,K> keySelector);
public C<G<K,T>> GroupBy<K>(Func<T,K> keySelector);
public C<G<K,E>> GroupBy<K,E>(Func<T,K> keySelector,
Func<T,E> elementSelector);
}
class O<T> : C<T>
{
public O<T> ThenBy<K>(Func<T,K> keySelector);
public O<T> ThenByDescending<K>(Func<T,K> keySelector);
}
class G<K,T> : C<T>
{
public K Key { get; }
}
上述方法會使用泛型委派型別 Func<T1,R>
和 Func<T1,T2,R>
,不過它們也可以在參數和結果型別中使用具有相同關聯性的其他委派或運算式樹狀結構類型。The methods above use the generic delegate types Func<T1,R>
and Func<T1,T2,R>
, but they could equally well have used other delegate or expression tree types with the same relationships in parameter and result types.
請注意和之間的建議關聯性, C<T>
O<T>
這可確保 ThenBy
和 ThenByDescending
方法只能在或的結果上 OrderBy
使用 OrderByDescending
。Notice the recommended relationship between C<T>
and O<T>
which ensures that the ThenBy
and ThenByDescending
methods are available only on the result of an OrderBy
or OrderByDescending
. 另請注意結果的建議圖形 GroupBy
--一連串序列,其中每個內部序列都有一個額外的 Key
屬性。Also notice the recommended shape of the result of GroupBy
-- a sequence of sequences, where each inner sequence has an additional Key
property.
System.Linq
命名空間會為實介面的任何型別提供查詢運算子模式的實作為 System.Collections.Generic.IEnumerable<T>
。The System.Linq
namespace provides an implementation of the query operator pattern for any type that implements the System.Collections.Generic.IEnumerable<T>
interface.
指派運算子Assignment operators
指派運算子會將新值指派給變數、屬性、事件或索引子元素。The assignment operators assign a new value to a variable, a property, an event, or an indexer element.
assignment
: unary_expression assignment_operator expression
;
assignment_operator
: '='
| '+='
| '-='
| '*='
| '/='
| '%='
| '&='
| '|='
| '^='
| '<<='
| right_shift_assignment
;
指派的左運算元必須是分類為變數、屬性存取、索引子存取或事件存取的運算式。The left operand of an assignment must be an expression classified as a variable, a property access, an indexer access, or an event access.
=
運算子稱為 簡單指派運算子。The =
operator is called the simple assignment operator. 它會將右運算元的值指派給左運算元所指定的變數、屬性或索引子元素。It assigns the value of the right operand to the variable, property, or indexer element given by the left operand. 簡單指派運算子的左運算元可能不是事件存取 (但如 類似欄位的事件) 中所述。The left operand of the simple assignment operator may not be an event access (except as described in Field-like events). 簡單指派運算子會在 簡單指派中描述。The simple assignment operator is described in Simple assignment.
運算子以外的指派運算子 =
稱為 複合指派運算子。The assignment operators other than the =
operator are called the compound assignment operators. 這些運算子會在兩個運算元上執行指定的運算,然後將產生的值指派給左運算元所指定的變數、屬性或索引子元素。These operators perform the indicated operation on the two operands, and then assign the resulting value to the variable, property, or indexer element given by the left operand. 複合指派運算子會在 複合指派中描述。The compound assignment operators are described in Compound assignment.
+=
-=
使用事件存取運算式作為左運算元的和運算子,稱為 事件指派運算子。The +=
and -=
operators with an event access expression as the left operand are called the event assignment operators. 沒有其他指派運算子適用于以事件存取作為左運算元。No other assignment operator is valid with an event access as the left operand. 事件指派運算子會在 事件指派中描述。The event assignment operators are described in Event assignment.
指派運算子是右向關聯的,表示作業是由右至左分組。The assignment operators are right-associative, meaning that operations are grouped from right to left. 例如,表單的運算式 a = b = c
會評估為 a = (b = c)
。For example, an expression of the form a = b = c
is evaluated as a = (b = c)
.
單一指派Simple assignment
=
運算子稱為簡單指派運算子。The =
operator is called the simple assignment operator.
如果簡單指派的左運算元是表單 E.P
或 E[Ei]
E
具有編譯時間類型的 dynamic
,則指派會動態繫結 (動態繫結) 。If the left operand of a simple assignment is of the form E.P
or E[Ei]
where E
has the compile-time type dynamic
, then the assignment is dynamically bound (Dynamic binding). 在此情況下,指派運算式的編譯時間類型是 dynamic
,而且下面所述的解析將會在執行時間根據的執行時間類型進行 E
。In this case the compile-time type of the assignment expression is dynamic
, and the resolution described below will take place at run-time based on the run-time type of E
.
在簡單的指派中,右運算元必須是可隱含轉換成左運算元類型的運算式。In a simple assignment, the right operand must be an expression that is implicitly convertible to the type of the left operand. 作業會將右運算元的值指派給左運算元所指定的變數、屬性或索引子元素。The operation assigns the value of the right operand to the variable, property, or indexer element given by the left operand.
簡單指派運算式的結果是指派給左運算元的值。The result of a simple assignment expression is the value assigned to the left operand. 結果與左運算元的類型相同,而且一律分類為值。The result has the same type as the left operand and is always classified as a value.
如果左運算元是屬性或索引子存取,則屬性或索引子必須有 set
存取子。If the left operand is a property or indexer access, the property or indexer must have a set
accessor. 如果不是這種情況,就會發生系結階段錯誤。If this is not the case, a binding-time error occurs.
簡單指派表單的執行時間處理是 x = y
由下列步驟所組成:The run-time processing of a simple assignment of the form x = y
consists of the following steps:
- 如果
x
分類為變數:Ifx
is classified as a variable:x
會評估以產生變數。x
is evaluated to produce the variable.y
會進行評估,並視需要透過隱含轉換轉換成的類型x
(隱含 轉換) 。y
is evaluated and, if required, converted to the type ofx
through an implicit conversion (Implicit conversions).- 如果所指定的變數
x
是 reference_type 的陣列元素,則會執行執行時間檢查,以確保計算的值y
與的陣列實例相容,其x
為元素。If the variable given byx
is an array element of a reference_type, a run-time check is performed to ensure that the value computed fory
is compatible with the array instance of whichx
is an element. 如果y
為null
,或如果隱含參考轉換 (隱含參考 轉換) 存在於所參考之y
陣列實例的實際元素類型中,則檢查會成功x
。The check succeeds ify
isnull
, or if an implicit reference conversion (Implicit reference conversions) exists from the actual type of the instance referenced byy
to the actual element type of the array instance containingx
. 否則會擲回System.ArrayTypeMismatchException
。Otherwise, aSystem.ArrayTypeMismatchException
is thrown. - 評估和轉換所產生的值
y
會儲存至評估所指定的位置x
。The value resulting from the evaluation and conversion ofy
is stored into the location given by the evaluation ofx
.
- 如果
x
分類為屬性或索引子存取:Ifx
is classified as a property or indexer access:- 如果不是) ,則為實例運算式 (如果
x
static
是,則為引數清單 (如果x
是,則會評估與相關聯的索引子存取)x
,而且結果會用於後續的set
存取子調用。The instance expression (ifx
is notstatic
) and the argument list (ifx
is an indexer access) associated withx
are evaluated, and the results are used in the subsequentset
accessor invocation. y
會進行評估,並視需要透過隱含轉換轉換成的類型x
(隱含 轉換) 。y
is evaluated and, if required, converted to the type ofx
through an implicit conversion (Implicit conversions).- 的
set
存取子x
會以計算的值y
做為其引數來叫用value
。Theset
accessor ofx
is invoked with the value computed fory
as itsvalue
argument.
- 如果不是) ,則為實例運算式 (如果
陣列共變數規則 (陣列共 變數) 允許陣列類型的值 A[]
為數組類型實例的參考 B[]
,但前提是已有隱含的參考轉換 B
A
。The array co-variance rules (Array covariance) permit a value of an array type A[]
to be a reference to an instance of an array type B[]
, provided an implicit reference conversion exists from B
to A
. 因為這些規則,指派給 reference_type 的陣列元素需要執行時間檢查,以確保所指派的值與陣列實例相容。Because of these rules, assignment to an array element of a reference_type requires a run-time check to ensure that the value being assigned is compatible with the array instance. 在範例中In the example
string[] sa = new string[10];
object[] oa = sa;
oa[0] = null; // Ok
oa[1] = "Hello"; // Ok
oa[2] = new ArrayList(); // ArrayTypeMismatchException
最後一個指派會導致擲回 System.ArrayTypeMismatchException
,因為 ArrayList
無法將實例儲存在的元素中 string[]
。the last assignment causes a System.ArrayTypeMismatchException
to be thrown because an instance of ArrayList
cannot be stored in an element of a string[]
.
當 struct_type 中宣告的屬性或索引子是指派的目標時,與屬性或索引子存取相關聯的實例運算式必須分類為變數。When a property or indexer declared in a struct_type is the target of an assignment, the instance expression associated with the property or indexer access must be classified as a variable. 如果實例運算式分類為值,就會發生系結階段錯誤。If the instance expression is classified as a value, a binding-time error occurs. 由於 成員存取,相同的規則也適用于欄位。Because of Member access, the same rule also applies to fields.
假設宣告如下:Given the declarations:
struct Point
{
int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int X {
get { return x; }
set { x = value; }
}
public int Y {
get { return y; }
set { y = value; }
}
}
struct Rectangle
{
Point a, b;
public Rectangle(Point a, Point b) {
this.a = a;
this.b = b;
}
public Point A {
get { return a; }
set { a = value; }
}
public Point B {
get { return b; }
set { b = value; }
}
}
在範例中in the example
Point p = new Point();
p.X = 100;
p.Y = 100;
Rectangle r = new Rectangle();
r.A = new Point(10, 10);
r.B = p;
p.X
p.Y
r.A
r.B
由於 p
和 r
都是變數,因此允許指派給、、和。the assignments to p.X
, p.Y
, r.A
, and r.B
are permitted because p
and r
are variables. 不過,在範例中However, in the example
Rectangle r = new Rectangle();
r.A.X = 10;
r.A.Y = 10;
r.B.X = 100;
r.B.Y = 100;
由於和不是變數,因此指派全都無效 r.A
r.B
。the assignments are all invalid, since r.A
and r.B
are not variables.
複合指派Compound assignment
如果複合指派的左運算元是表單 E.P
或 E[Ei]
E
具有編譯時間類型的 dynamic
,則指派會動態繫結 (動態繫結) 。If the left operand of a compound assignment is of the form E.P
or E[Ei]
where E
has the compile-time type dynamic
, then the assignment is dynamically bound (Dynamic binding). 在此情況下,指派運算式的編譯時間類型是 dynamic
,而且下面所述的解析將會在執行時間根據的執行時間類型進行 E
。In this case the compile-time type of the assignment expression is dynamic
, and the resolution described below will take place at run-time based on the run-time type of E
.
藉 x op= y
由套用二元運算子多載解析 (二元運算子 多載解析) 和寫入作業的方式來處理表單的作業 x op y
。An operation of the form x op= y
is processed by applying binary operator overload resolution (Binary operator overload resolution) as if the operation was written x op y
. 如此一來,Then,
- 如果所選運算子的傳回型別可隱含轉換成的型別
x
,則作業會評估為x = x op y
,但是x
只會評估一次。If the return type of the selected operator is implicitly convertible to the type ofx
, the operation is evaluated asx = x op y
, except thatx
is evaluated only once. - 否則,如果選取的運算子是預先定義的運算子,則如果所選運算子的傳回型別明確地轉換成的型別
x
,而且如果y
可以隱含地轉換成的型別x
或運算子是移位運算子,則作業會評估為x = (T)(x op y)
,其中T
是的型別,x
但是x
只會評估一次。Otherwise, if the selected operator is a predefined operator, if the return type of the selected operator is explicitly convertible to the type ofx
, and ify
is implicitly convertible to the type ofx
or the operator is a shift operator, then the operation is evaluated asx = (T)(x op y)
, whereT
is the type ofx
, except thatx
is evaluated only once. - 否則,複合指派是不正確,而且會發生系結階段錯誤。Otherwise, the compound assignment is invalid, and a binding-time error occurs.
「只評估一次」一詞表示在的評估中 x op y
,會暫時儲存任何組成運算式的結果, x
然後在執行指派給時重複使用 x
。The term "evaluated only once" means that in the evaluation of x op y
, the results of any constituent expressions of x
are temporarily saved and then reused when performing the assignment to x
. 例如,在指派中 A()[B()] += C()
,其中是傳回的 A
方法 int[]
,且 B
和都是傳回的 C
方法 int
,則只會叫用一次方法,順序為 A
B
C
。For example, in the assignment A()[B()] += C()
, where A
is a method returning int[]
, and B
and C
are methods returning int
, the methods are invoked only once, in the order A
, B
, C
.
當複合指派的左運算元是屬性存取或索引子存取時,屬性或索引子必須同時具有存取子 get
和存取子 set
。When the left operand of a compound assignment is a property access or indexer access, the property or indexer must have both a get
accessor and a set
accessor. 如果不是這種情況,就會發生系結階段錯誤。If this is not the case, a binding-time error occurs.
上述的第二個規則允許 x op= y
x = (T)(x op y)
在特定內容中進行評估。The second rule above permits x op= y
to be evaluated as x = (T)(x op y)
in certain contexts. 當左運算元的類型為、、、或時,規則就會存在,讓預先定義的運算子可以當做複合運算子使用 sbyte
byte
short
ushort
char
。The rule exists such that the predefined operators can be used as compound operators when the left operand is of type sbyte
, byte
, short
, ushort
, or char
. 即使兩個引數都是這些類型的其中之一,預先定義的運算子仍會產生類型的結果 int
,如 二進位數值升級中所述。Even when both arguments are of one of those types, the predefined operators produce a result of type int
, as described in Binary numeric promotions. 因此,若沒有轉換,則無法將結果指派給左運算元。Thus, without a cast it would not be possible to assign the result to the left operand.
預先定義之運算子的規則直覺效果,就是 x op= y
如果 x op y
允許和都是允許的 x = y
。The intuitive effect of the rule for predefined operators is simply that x op= y
is permitted if both of x op y
and x = y
are permitted. 在範例中In the example
byte b = 0;
char ch = '\0';
int i = 0;
b += 1; // Ok
b += 1000; // Error, b = 1000 not permitted
b += i; // Error, b = i not permitted
b += (byte)i; // Ok
ch += 1; // Error, ch = 1 not permitted
ch += (char)1; // Ok
每個錯誤的直覺原因是對應的簡單指派也會發生錯誤。the intuitive reason for each error is that a corresponding simple assignment would also have been an error.
這也表示複合指派作業支援提升的作業。This also means that compound assignment operations support lifted operations. 在範例中In the example
int? i = 0;
i += 1; // Ok
使用提升運算子 +(int?,int?)
。the lifted operator +(int?,int?)
is used.
事件指派Event assignment
如果 or 運算子的左運算元 +=
-=
分類為事件存取,則運算式的評估方式如下:If the left operand of a +=
or -=
operator is classified as an event access, then the expression is evaluated as follows:
- 評估事件存取的實例運算式(如果有的話)。The instance expression, if any, of the event access is evaluated.
+=
-=
系統會評估 or 運算子的右運算元,並在必要時,透過隱含轉換 (隱含轉換) 來轉換成左運算元的類型。The right operand of the+=
or-=
operator is evaluated, and, if required, converted to the type of the left operand through an implicit conversion (Implicit conversions).- 系統會叫用事件的事件存取子,並在評估之後、以及(如有必要)轉換之後,使用由右運算元組成的引數清單。An event accessor of the event is invoked, with argument list consisting of the right operand, after evaluation and, if necessary, conversion. 如果運算子是,則會叫用
+=
add
存取子; 如果運算子是-=
,則remove
會叫用存取子。If the operator was+=
, theadd
accessor is invoked; if the operator was-=
, theremove
accessor is invoked.
事件指派運算式不會產生值。An event assignment expression does not yield a value. 因此,事件指派運算式只在 statement_expression (運算式語句) 的內容中有效。Thus, an event assignment expression is valid only in the context of a statement_expression (Expression statements).
運算式Expression
運算式 可以是 non_assignment_expression 或 指派。An expression is either a non_assignment_expression or an assignment.
expression
: non_assignment_expression
| assignment
;
non_assignment_expression
: conditional_expression
| lambda_expression
| query_expression
;
常數運算式Constant expressions
Constant_expression 是可在編譯時期完整評估的運算式。A constant_expression is an expression that can be fully evaluated at compile-time.
constant_expression
: expression
;
常數運算式必須是 null
常值或具有下列其中一種類型的值:、、、、、、、、、、、、、、 sbyte
byte
short
ushort
int
uint
long
ulong
char
float
double
decimal
bool
object
string
或任何列舉類型。A constant expression must be the null
literal or a value with one of the following types: sbyte
, byte
, short
, ushort
, int
, uint
, long
, ulong
, char
, float
, double
, decimal
, bool
, object
, string
, or any enumeration type. 常數運算式中只允許下列結構:Only the following constructs are permitted in constant expressions:
- 常值 (包括
null
常值) 。Literals (including thenull
literal). const
類別和結構類型成員的參考。References toconst
members of class and struct types.- 列舉類型成員的參考。References to members of enumeration types.
const
參數或本機變數的參考References toconst
parameters or local variables- 括弧內的子運算式,也就是常數運算式。Parenthesized sub-expressions, which are themselves constant expressions.
- Cast 運算式(如果目標型別是以上所列的其中一種類型的話)。Cast expressions, provided the target type is one of the types listed above.
checked
和unchecked
運算式checked
andunchecked
expressions- 預設值運算式Default value expressions
- Nameof 運算式Nameof expressions
- 預先定義的
+
、、-
!
和~
一元運算子。The predefined+
,-
,!
, and~
unary operators. - 預先定義的、、、、、、、、、、、、、、、、
+
-
*
/
%
<<
>>
&
|
^
&&
||
==
!=
<
>
<=
和>=
二元運算子,提供的每個運算元都是上述類型。The predefined+
,-
,*
,/
,%
,<<
,>>
,&
,|
,^
,&&
,||
,==
,!=
,<
,>
,<=
, and>=
binary operators, provided each operand is of a type listed above. ?:
條件運算子。The?:
conditional operator.
常數運算式中允許下列轉換:The following conversions are permitted in constant expressions:
- 身分識別轉換Identity conversions
- 數值轉換Numeric conversions
- 列舉轉換Enumeration conversions
- 常數運算式轉換Constant expression conversions
- 隱含和明確的參考轉換,前提是轉換的來源是評估為 null 值的常數運算式。Implicit and explicit reference conversions, provided that the source of the conversions is a constant expression that evaluates to the null value.
常數運算式中不允許其他轉換,包括非 null 值的裝箱、取消裝箱和隱含參考轉換。Other conversions including boxing, unboxing and implicit reference conversions of non-null values are not permitted in constant expressions. 例如:For example:
class C {
const object i = 5; // error: boxing conversion not permitted
const object str = "hello"; // error: implicit reference conversion
}
因為需要進行裝箱轉換,所以我的初始化是錯誤。the initialization of i is an error because a boxing conversion is required. 因為需要非 null 值的隱含參考轉換,所以 str 的初始化是錯誤。The initialization of str is an error because an implicit reference conversion from a non-null value is required.
每次運算式滿足上述的需求時,就會在編譯時期評估運算式。Whenever an expression fulfills the requirements listed above, the expression is evaluated at compile-time. 即使運算式是包含非常數結構之較大運算式的子運算式,也是如此。This is true even if the expression is a sub-expression of a larger expression that contains non-constant constructs.
常數運算式的編譯時間評估會使用與非常數運算式之執行時間評估相同的規則,但在此情況下,執行時間評估會擲回例外狀況,編譯時間評估會導致編譯時期錯誤發生。The compile-time evaluation of constant expressions uses the same rules as run-time evaluation of non-constant expressions, except that where run-time evaluation would have thrown an exception, compile-time evaluation causes a compile-time error to occur.
除非在內容中明確放置常數運算式,否則在 unchecked
運算式的編譯時間評估期間,整數型別算數運算和轉換期間發生的溢位,一律會造成編譯時期錯誤 (常數運算式) 。Unless a constant expression is explicitly placed in an unchecked
context, overflows that occur in integral-type arithmetic operations and conversions during the compile-time evaluation of the expression always cause compile-time errors (Constant expressions).
常數運算式會出現在下列內容中。Constant expressions occur in the contexts listed below. 在這些內容中,如果無法在編譯時期完整評估運算式,就會發生編譯時期錯誤。In these contexts, a compile-time error occurs if an expression cannot be fully evaluated at compile-time.
- 常數宣告 (常數) 。Constant declarations (Constants).
- 列舉 成員) (列舉成員宣告。Enumeration member declarations (Enum members).
- 正式參數清單 (方法參數 的預設引數) Default arguments of formal parameter lists (Method parameters)
case``switch
switch 語句) (語句的標籤。case
labels of aswitch
statement (The switch statement).goto case
語句 (goto 語句) 。goto case
statements (The goto statement).- 陣列建立運算式中的維度長度 (包含初始化 運算式的陣列建立運算式) 。Dimension lengths in an array creation expression (Array creation expressions) that includes an initializer.
- 屬性 (屬性) 。Attributes (Attributes).
隱含常數運算式 轉換 (隱含常數運算式轉換) 允許將類型的常數運算式 int
轉換成 sbyte
、 byte
、 short
、 ushort
、 uint
或 ulong
,前提是常數運算式的值是在目的地類型的範圍內。An implicit constant expression conversion (Implicit constant expression conversions) permits a constant expression of type int
to be converted to sbyte
, byte
, short
, ushort
, uint
, or ulong
, provided the value of the constant expression is within the range of the destination type.
布林運算式Boolean expressions
Boolean_expression 是在特定內容中直接或透過應用程式產生型別結果的運算式, bool
operator true
如下列所指定。A boolean_expression is an expression that yields a result of type bool
; either directly or through application of operator true
in certain contexts as specified in the following.
boolean_expression
: expression
;
If_statement (if 語句的控制條件運算式) 、 while_statement (while 語句 ) 、do_statement ( do 語句) ,或 for_statement (for 語句) 是 boolean_expression。The controlling conditional expression of an if_statement (The if statement), while_statement (The while statement), do_statement (The do statement), or for_statement (The for statement) is a boolean_expression. 運算子的控制條件運算式 ?:
(條件運算子) 遵循與 boolean_expression 相同的規則,但基於運算子優先順序的原因,會分類為 conditional_or_expression。The controlling conditional expression of the ?:
operator (Conditional operator) follows the same rules as a boolean_expression, but for reasons of operator precedence is classified as a conditional_or_expression.
需要 boolean_expression 才能 E
產生型別的值,如下所示 bool
:A boolean_expression E
is required to be able to produce a value of type bool
, as follows:
- 如果在
E
bool
執行時間可隱含轉換為,則會套用隱含轉換。IfE
is implicitly convertible tobool
then at runtime that implicit conversion is applied. - 否則,一元運算子多載解析 (一元運算子 多載解析) 用來在上尋找運算子的唯一最佳實作為
true
E
,並在執行時間套用該實作為。Otherwise, unary operator overload resolution (Unary operator overload resolution) is used to find a unique best implementation of operatortrue
onE
, and that implementation is applied at runtime. - 如果找不到這類運算子,就會發生系結階段錯誤。If no such operator is found, a binding-time error occurs.
DBBool
資料庫布林值型別中的結構類型提供實和的型別 operator true
範例 operator false
。The DBBool
struct type in Database boolean type provides an example of a type that implements operator true
and operator false
.