Prefix increment and decrement operators

++ unary-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.

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 (§7.3.3) is applied to select a specific operator implementation. Predefined ++ and -- operators exist for the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, and any enum type. 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. 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.

The run-time processing of a prefix increment or decrement operation of the form ++x or --x consists of the following steps:

· If x is classified as a variable:

o x is evaluated to produce the variable.

o The selected operator is invoked with the value of x as its argument.

o The value returned by the operator is stored in the location given by the evaluation of x.

o The value returned by the operator becomes the result of the operation.

· If x is classified as a property or indexer access:

o The instance expression (if x is not static) and the argument list (if x is an indexer access) associated with x are evaluated, and the results are used in the subsequent get and set accessor invocations.

o The get accessor of x is invoked.

o The selected operator is invoked with the value returned by the get accessor as its argument.

o The set accessor of x is invoked with the value returned by the operator as its value argument.

o The value returned by the operator becomes the result of the operation.

The ++ and -- operators also support postfix notation (§7.6.9). 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. In either case, x itself has the same value after the operation.

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

A cast-expression is used to explicitly convert an expression to a given type.

( type ) unary-expression

A cast-expression of the form (T)E, where T is a type and E is a unary-expression, performs an explicit conversion (§6.2) of the value of E to type 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. The result is always classified as a value, even if E denotes a variable.

The grammar for a cast-expression leads to certain syntactic ambiguities. 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).

To resolve cast-expression ambiguities, the following rule exists: A sequence of one or more tokens (§2.3.3) 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.

· 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 (§2.4.1), a literal (§2.4.4), or any keyword (§2.4.3) except as and is.

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. 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.

From the disambiguation rule it follows that, if x and y are identifiers, (x)y, (x)(y), and (x)(-y) are cast-expressions, but (x)-y is not, even if x identifies a type. However, if x is a keyword that identifies a predefined type (such as int), then all four forms are cast-expressions (because such a keyword could not possibly be an expression by itself).

Await expressions

The await operator is used to suspend evaluation of the enclosing async function until the asynchronous operation represented by the operand has completed.

await unary-expression

An await-expression is only allowed in the body of an async function (§10.14). Within the nearest enclosing async function, an await-expression may not occur in these places:

· Inside a nested (non-async) anonymous function

· In a catch or finally block of a try-statement

· Inside the block of a lock-statement

· In an unsafe context

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.

Inside of an async function, await cannot be used as an identifier. There is therefore no syntactic ambiguity between await-expressions and various expressions involving identifiers. Outside of async functions, await acts as a normal identifier.

The operand of an await-expression is called the task. It represents an asynchronous operation that may or may not be complete at the time the await-expression is evaluated. 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

The task of an await expression is required to be awaitable. An expression t is awaitable if one of the following holds:

· t is of compile time type dynamic

· t has an accessible instance or extension method called GetAwaiter with no parameters and no type parameters, and a return type A for which all of the following hold:

o A implements the interface System.Runtime.CompilerServices.INotifyCompletion (hereafter known as INotifyCompletion for brevity)

o A has an accessible, readable instance property IsCompleted of type bool

o A has an accessible instance method GetResult with no parameters and no type parameters

The purpose of the GetAwaiter method is to obtain an awaiter for the task. The type A is called the awaiter type for the await expression.

The purpose of the IsCompleted property is to determine if the task is already complete. If so, there is no need to suspend evaluation.

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.

The purpose of the GetResult method is to obtain the outcome of the task once it is complete. This outcome may be successful completion, possibly with a result value, or it may be an exception which is thrown by the GetResult method.

Последнее изменение этой страницы: 2016-12-14; Нарушение авторского права страницы

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - (0.008 с.)