EspressioniExpressions

Un'espressione è una sequenza di operatori e operandi.An expression is a sequence of operators and operands. Questo capitolo definisce la sintassi, l'ordine di valutazione degli operandi e degli operatori e il significato delle espressioni.This chapter defines the syntax, order of evaluation of operands and operators, and meaning of expressions.

Classificazioni di espressioniExpression classifications

Un'espressione viene classificata nei seguenti modi:An expression is classified as one of the following:

  • Valore.A value. Ad ogni valore è associato un tipo.Every value has an associated type.
  • Variabile.A variable. A ogni variabile è associato un tipo, ovvero il tipo dichiarato della variabile.Every variable has an associated type, namely the declared type of the variable.
  • Spazio dei nomi.A namespace. Un'espressione con questa classificazione può essere visualizzata solo come parte sinistra di un member_access (accesso ai membri).An expression with this classification can only appear as the left hand side of a member_access (Member access). In qualsiasi altro contesto, un'espressione classificata come uno spazio dei nomi causa un errore in fase di compilazione.In any other context, an expression classified as a namespace causes a compile-time error.
  • Tipo.A type. Un'espressione con questa classificazione può essere visualizzata solo come parte sinistra di un member_access (accesso ai membri) o come operando per l'operatore di as (operatore as), l'operatore is (l'operatore is) o l'operatore typeof (operatore 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 the as operator (The as operator), the is operator (The is operator), or the typeof operator (The typeof operator). In qualsiasi altro contesto, un'espressione classificata come tipo causa un errore in fase di compilazione.In any other context, an expression classified as a type causes a compile-time error.
  • Un gruppo di metodi, ovvero un set di metodi di overload risultante da una ricerca di membri (ricerca di membri).A method group, which is a set of overloaded methods resulting from a member lookup (Member lookup). A un gruppo di metodi può essere associata un'espressione di istanza e un elenco di argomenti di tipo associato.A method group may have an associated instance expression and an associated type argument list. Quando viene richiamato un metodo di istanza, il risultato della valutazione dell'espressione di istanza diventa l'istanza rappresentata da this (questo accesso).When an instance method is invoked, the result of evaluating the instance expression becomes the instance represented by this (This access). Un gruppo di metodi è consentito in un invocation_expression (espressioni di chiamata), un delegate_creation_expression (espressioni dicreazione di delegati) e come lato sinistro di un operatore is e può essere convertito in modo implicito in un tipo delegato compatibile (conversioni di gruppi di metodi).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 qualsiasi altro contesto, un'espressione classificata come un gruppo di metodi causa un errore in fase di compilazione.In any other context, an expression classified as a method group causes a compile-time error.
  • Valore letterale null.A null literal. Un'espressione con questa classificazione può essere convertita in modo implicito in un tipo di riferimento o un tipo Nullable.An expression with this classification can be implicitly converted to a reference type or nullable type.
  • Funzione anonima.An anonymous function. Un'espressione con questa classificazione può essere convertita in modo implicito in un tipo delegato o un tipo di albero delle espressioni compatibile.An expression with this classification can be implicitly converted to a compatible delegate type or expression tree type.
  • Accesso A una proprietà.A property access. A ogni accesso alle proprietà è associato un tipo, ovvero il tipo della proprietà.Every property access has an associated type, namely the type of the property. Un accesso a proprietà può inoltre avere un'espressione di istanza associata.Furthermore, a property access may have an associated instance expression. Quando viene richiamata una funzione di accesso (il blocco get o set) di una proprietà dell'istanza, il risultato della valutazione dell'espressione di istanza diventa l'istanza rappresentata da this (questo accesso).When an accessor (the get or set block) of an instance property access is invoked, the result of evaluating the instance expression becomes the instance represented by this (This access).
  • Accesso a un evento.An event access. A ogni accesso agli eventi è associato un tipo, ovvero il tipo dell'evento.Every event access has an associated type, namely the type of the event. Inoltre, è possibile che a un accesso a un evento sia associata un'espressione di istanza.Furthermore, an event access may have an associated instance expression. È possibile che l'accesso agli eventi venga visualizzato come operando sinistro degli operatori += e -= (assegnazione evento).An event access may appear as the left hand operand of the += and -= operators (Event assignment). In qualsiasi altro contesto, un'espressione classificata come accesso agli eventi causa un errore in fase di compilazione.In any other context, an expression classified as an event access causes a compile-time error.
  • Accesso dell'indicizzatore.An indexer access. A ogni accesso dell'indicizzatore è associato un tipo, ovvero il tipo di elemento dell'indicizzatore.Every indexer access has an associated type, namely the element type of the indexer. Inoltre, un accesso all'indicizzatore ha un'espressione di istanza associata e un elenco di argomenti associato.Furthermore, an indexer access has an associated instance expression and an associated argument list. Quando viene richiamata una funzione di accesso (il blocco get o set) di un indicizzatore, il risultato della valutazione dell'espressione di istanza diventa l'istanza rappresentata da this (questo accesso) e il risultato della valutazione dell'elenco di argomenti diventa l'elenco di parametri della chiamata.When an accessor (the get or set block) of an indexer access is invoked, the result of evaluating the instance expression becomes the instance represented by this (This access), and the result of evaluating the argument list becomes the parameter list of the invocation.
  • Niente.Nothing. Questo errore si verifica quando l'espressione è una chiamata di un metodo con un tipo restituito di void.This occurs when the expression is an invocation of a method with a return type of void. Un'espressione classificata come Nothing è valida solo nel contesto di un statement_expression (istruzioni Expression).An expression classified as nothing is only valid in the context of a statement_expression (Expression statements).

Il risultato finale di un'espressione non è mai uno spazio dei nomi, un tipo, un gruppo di metodi o l'accesso agli eventi.The final result of an expression is never a namespace, type, method group, or event access. Piuttosto, come indicato in precedenza, queste categorie di espressioni sono costrutti intermedi che sono consentiti solo in determinati contesti.Rather, as noted above, these categories of expressions are intermediate constructs that are only permitted in certain contexts.

Un accesso a una proprietà o un indicizzatore viene sempre riclassificato come valore eseguendo una chiamata della funzione di accesso Get o della funzionedi accesso 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. La funzione di accesso specifica è determinata dal contesto dell'accesso alla proprietà o all'indicizzatore: se l'accesso è la destinazione di un'assegnazione, viene richiamata la funzione di accesso set per assegnare un nuovo valore (assegnazione semplice).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). In caso contrario, viene richiamata la funzione di accesso get per ottenere il valore corrente (valori di espressioni).Otherwise, the get accessor is invoked to obtain the current value (Values of expressions).

Valori delle espressioniValues of expressions

Per la maggior parte dei costrutti che coinvolgono un'espressione, è necessario che l'espressione denoti un valore.Most of the constructs that involve an expression ultimately require the expression to denote a value. In questi casi, se l'espressione effettiva indica uno spazio dei nomi, un tipo, un gruppo di metodi o Nothing, si verifica un errore in fase di compilazione.In such cases, if the actual expression denotes a namespace, a type, a method group, or nothing, a compile-time error occurs. Tuttavia, se l'espressione denota un accesso a una proprietà, un accesso all'indicizzatore o una variabile, il valore della proprietà, dell'indicizzatore o della variabile viene sostituito in modo implicito: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:

  • Il valore di una variabile è semplicemente il valore attualmente archiviato nella posizione di archiviazione identificata dalla variabile.The value of a variable is simply the value currently stored in the storage location identified by the variable. Una variabile deve essere considerata definitivamente assegnata (assegnazione definita) prima di poter ottenere il relativo valore o in caso contrario si verifica un errore in fase di compilazione.A variable must be considered definitely assigned (Definite assignment) before its value can be obtained, or otherwise a compile-time error occurs.
  • Il valore di un'espressione di accesso alla proprietà viene ottenuto richiamando la funzione di accesso Get della proprietà.The value of a property access expression is obtained by invoking the get accessor of the property. Se la proprietà non dispone di una funzione di accesso get, si verifica un errore in fase di compilazione.If the property has no get accessor, a compile-time error occurs. In caso contrario, viene eseguita una chiamata del membro della funzione (controllo della fase di compilazione della risoluzione dell'overload dinamico) e il risultato della chiamata diventa il valore dell'espressione di accesso alla proprietà.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.
  • Il valore di un'espressione di accesso dell'indicizzatore viene ottenuto richiamando la funzione di accesso Get dell'indicizzatore.The value of an indexer access expression is obtained by invoking the get accessor of the indexer. Se l'indicizzatore non dispone di una funzione di accesso get, si verifica un errore in fase di compilazione.If the indexer has no get accessor, a compile-time error occurs. In caso contrario, la chiamata di un membro di funzione (controllo della fase di compilazione della risoluzione dell'overload dinamico) viene eseguita con l'elenco di argomenti associato all'espressione di accesso dell'indicizzatore e il risultato della chiamata diventa il valore dell'espressione di accesso dell'indicizzatore.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.

Associazione statica e dinamicaStatic and Dynamic Binding

Il processo di determinazione del significato di un'operazione basata sul tipo o sul valore delle espressioni costituenti (argomenti, operandi e destinatari) viene spesso definito 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. Ad esempio, il significato di una chiamata al metodo viene determinato in base al tipo del destinatario e degli argomenti.For instance the meaning of a method call is determined based on the type of the receiver and arguments. Il significato di un operatore viene determinato in base al tipo degli operandi.The meaning of an operator is determined based on the type of its operands.

Il C# significato di un'operazione viene in genere determinato in fase di compilazione, in base al tipo in fase di compilazione delle espressioni costituenti.In C# the meaning of an operation is usually determined at compile-time, based on the compile-time type of its constituent expressions. Analogamente, se un'espressione contiene un errore, l'errore viene rilevato e segnalato dal compilatore.Likewise, if an expression contains an error, the error is detected and reported by the compiler. Questo approccio è noto come associazione statica.This approach is known as static binding.

Tuttavia, se un'espressione è un'espressione dinamica (ad esempio, ha il tipo dynamic) indica che qualsiasi associazione di cui fa parte deve essere basata sul tipo in fase di esecuzione (ovvero il tipo effettivo dell'oggetto che denota in fase di esecuzione) anziché il tipo in fase di compilazione.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. Il binding di tale operazione viene quindi rinviato fino al momento in cui l'operazione deve essere eseguita durante l'esecuzione del programma.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. Questa operazione viene definita associazione dinamica.This is referred to as dynamic binding.

Quando un'operazione è associata dinamicamente, il compilatore esegue il controllo minimo o no.When an operation is dynamically bound, little or no checking is performed by the compiler. In alternativa, se l'associazione in fase di esecuzione ha esito negativo, gli errori vengono segnalati come eccezioni in fase di esecuzione.Instead if the run-time binding fails, errors are reported as exceptions at run-time.

Le operazioni seguenti in C# sono soggette all'associazione:The following operations in C# are subject to binding:

  • Accesso ai membri: e.MMember access: e.M
  • Chiamata al metodo: e.M(e1, ..., eN)Method invocation: e.M(e1, ..., eN)
  • Chiamata al delegato:e(e1, ..., eN)Delegate invocation:e(e1, ..., eN)
  • Accesso agli elementi: e[e1, ..., eN]Element access: e[e1, ..., eN]
  • Creazione oggetto: new C(e1, ..., eN)Object creation: new C(e1, ..., eN)
  • Operatori unari di overload: +, -, !, ~, ++, --, true``falseOverloaded unary operators: +, -, !, ~, ++, --, true, false
  • Operatori binari di overload: +, -, *, /, %, &, &&, |, ||, ??, ^, <<, >>, ==,!=, >, <, >=, <=Overloaded binary operators: +, -, *, /, %, &, &&, |, ||, ??, ^, <<, >>, ==,!=, >, <, >=, <=
  • Operatori di assegnazione: =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=Assignment operators: =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
  • Conversioni implicite ed espliciteImplicit and explicit conversions

Quando non sono implicate espressioni dinamiche C# , il valore predefinito è l'associazione statica, il che significa che i tipi in fase di compilazione delle espressioni costituenti vengono utilizzati nel processo di selezione.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. Tuttavia, quando una delle espressioni costitutive nelle operazioni elencate in precedenza è un'espressione dinamica, l'operazione viene associata in modo dinamico.However, when one of the constituent expressions in the operations listed above is a dynamic expression, the operation is instead dynamically bound.

Tempo di bindingBinding-time

L'associazione statica viene eseguita in fase di compilazione, mentre l'associazione dinamica avviene in fase di esecuzione.Static binding takes place at compile-time, whereas dynamic binding takes place at run-time. Nelle sezioni seguenti il termine Binding-Time si riferisce al runtime o alla fase di compilazione, a seconda del momento in cui si verifica l'associazione.In the following sections, the term binding-time refers to either compile-time or run-time, depending on when the binding takes place.

Nell'esempio seguente vengono illustrate le nozioni di associazione statica e dinamica e del tempo di binding: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)

Le prime due chiamate sono associate in modo statico: l'overload di Console.WriteLine viene scelto in base al tipo in fase di compilazione del relativo argomento.The first two calls are statically bound: the overload of Console.WriteLine is picked based on the compile-time type of their argument. In questo modo, il tempo di binding è in fase di compilazione.Thus, the binding-time is compile-time.

La terza chiamata viene associata in modo dinamico: l'overload di Console.WriteLine viene scelto in base al tipo in fase di esecuzione del relativo argomento.The third call is dynamically bound: the overload of Console.WriteLine is picked based on the run-time type of its argument. Questo problema si verifica perché l'argomento è un'espressione dinamica. il tipo in fase di compilazione è dynamic.This happens because the argument is a dynamic expression -- its compile-time type is dynamic. Il tempo di binding per la terza chiamata è quindi in fase di esecuzione.Thus, the binding-time for the third call is run-time.

Associazione dinamicaDynamic binding

Lo scopo dell'associazione dinamica consiste nel consentire C# ai programmi di interagire con gli oggetti dinamici, ovvero gli oggetti che non seguono le regole normali del C# sistema di tipi.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. È possibile che gli oggetti dinamici siano oggetti di altri linguaggi di programmazione con sistemi di tipi diversi o che siano oggetti a livello di codice per implementare la propria semantica di binding per diverse operazioni.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.

Il meccanismo mediante il quale un oggetto dinamico implementa la propria semantica è definito dall'implementazione.The mechanism by which a dynamic object implements its own semantics is implementation defined. Una data interfaccia definita, di nuovo implementata, è implementata dagli oggetti dinamici per segnalare al C# Runtime che hanno una semantica speciale.A given interface -- again implementation defined -- is implemented by dynamic objects to signal to the C# run-time that they have special semantics. Pertanto, ogni volta che le operazioni su un oggetto dinamico vengono associate in modo dinamico, la relativa semantica di binding C# , invece di quelle di come specificato in questo documento, assume la forma.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.

Sebbene lo scopo dell'associazione dinamica sia consentire l'interoperabilità con oggetti dinamici C# , consente l'associazione dinamica su tutti gli oggetti, indipendentemente dal fatto che siano dinamici o meno.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. Ciò consente un'integrazione più uniforme degli oggetti dinamici, perché i risultati delle operazioni su di essi non possono essere oggetti dinamici, ma sono ancora di un tipo sconosciuto al programmatore in fase di compilazione.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. Inoltre, l'associazione dinamica consente di eliminare codice basato su reflection con errori anche se nessun oggetto è soggetto ad oggetti dinamici.Also dynamic binding can help eliminate error-prone reflection-based code even when no objects involved are dynamic objects.

Le sezioni seguenti descrivono per ogni costrutto nel linguaggio esattamente quando viene applicato il binding dinamico, il controllo del tempo di compilazione, se presente, e il risultato della fase di compilazione e la classificazione delle espressioni.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.

Tipi di espressioni costituentiTypes of constituent expressions

Quando un'operazione viene associata in modo statico, il tipo di un'espressione costituente (ad esempio un ricevitore, un argomento, un indice o un operando) viene sempre considerato il tipo in fase di compilazione dell'espressione.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.

Quando un'operazione viene associata dinamicamente, il tipo di un'espressione costituente viene determinato in modi diversi a seconda del tipo in fase di compilazione dell'espressione costituente: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:

  • Un'espressione costituente di tipo in fase di compilazione dynamic viene considerata come il tipo del valore effettivo restituito dall'espressione in fase di esecuzioneA constituent expression of compile-time type dynamic is considered to have the type of the actual value that the expression evaluates to at runtime
  • Un'espressione costituente il cui tipo in fase di compilazione è un parametro di tipo è considerato il tipo a cui è associato il parametro di tipo in fase di esecuzioneA 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
  • In caso contrario, l'espressione costituente viene considerata come il tipo in fase di compilazione.Otherwise the constituent expression is considered to have its compile-time type.

OperatoriOperators

Le espressioni sono costruite da operandi e operatori.Expressions are constructed from operands and operators. Gli operatori di un'espressione indicano le operazioni che devono essere eseguite sugli operandi.The operators of an expression indicate which operations to apply to the operands. Alcuni esempi di operatori sono +, -, *, / e new,Examples of operators include +, -, *, /, and new. mentre i valori effettivi, i campi, le variabili locali e le espressioni sono esempi di operandi.Examples of operands include literals, fields, local variables, and expressions.

Sono disponibili tre tipi di operatori:There are three kinds of operators:

  • Operatori unari.Unary operators. Gli operatori unari accettano un operando e utilizzano la notazione del prefisso (ad esempio --x) o la notazione suffissa, ad esempio x++.The unary operators take one operand and use either prefix notation (such as --x) or postfix notation (such as x++).
  • Operatori binari.Binary operators. Gli operatori binari accettano due operandi e utilizzano la notazione infissa, ad esempio x + y.The binary operators take two operands and all use infix notation (such as x + y).
  • Operatore ternario.Ternary operator. Esiste solo un operatore ternario, ?:; accetta tre operandi e usa la notazione infissa (c ? x : y).Only one ternary operator, ?:, exists; it takes three operands and uses infix notation (c ? x : y).

L'ordine di valutazione degli operatori in un'espressione è determinato dalla precedenza e dall' associatività degli operatori (precedenza e associativitàdegli operatori).The order of evaluation of operators in an expression is determined by the precedence and associativity of the operators (Operator precedence and associativity).

Gli operandi in un'espressione vengono valutati da sinistra a destra.Operands in an expression are evaluated from left to right. Ad esempio, in F(i) + G(i++) * H(i), il metodo F viene chiamato usando il valore precedente di i, quindi il metodo G viene chiamato con il valore precedente di ie, infine, il metodo H viene chiamato con il nuovo valore di 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. Questa operazione è separata da e non è correlata alla precedenza degli operatori.This is separate from and unrelated to operator precedence.

Certi operatori possono essere sottoposti a overload.Certain operators can be overloaded. L'overload degli operatori consente di specificare implementazioni di operatori definiti dall'utente per le operazioni in cui uno o entrambi gli operandi sono di una classe o di un tipo struct definito dall'utente (Overload degli operatori).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).

Precedenza e associatività degli operatoriOperator precedence and associativity

Se un'espressione contiene più operatori, la precedenza degli operatori determina l'ordine in cui vengono valutati i singoli operatori.When an expression contains multiple operators, the precedence of the operators controls the order in which the individual operators are evaluated. Ad esempio, l'espressione x + y * z viene valutata come x + (y * z) perché l'operatore * ha precedenza più alta rispetto all'operatore Binary +.For example, the expression x + y * z is evaluated as x + (y * z) because the * operator has higher precedence than the binary + operator. La precedenza di un operatore viene stabilita dalla definizione della produzione della grammatica associata.The precedence of an operator is established by the definition of its associated grammar production. Ad esempio, un additive_expression è costituito da una sequenza di multiplicative_expression, separate da operatori + o -, in modo da concedere agli operatori + e - la precedenza rispetto agli operatori *, /e %.For example, an additive_expression consists of a sequence of multiplicative_expressions separated by + or - operators, thus giving the + and - operators lower precedence than the *, /, and % operators.

La tabella seguente riepiloga tutti gli operatori in ordine di precedenza, dal più alto al più basso:The following table summarizes all operators in order of precedence from highest to lowest:

SectionSection CategoriaCategory OperatoriOperators
Espressioni primariePrimary expressions PrimaryPrimary x.y f(x) a[x] x++ x-- new typeof default checked unchecked delegatex.y f(x) a[x] x++ x-- new typeof default checked unchecked delegate
Operatori unariUnary operators UnarioUnary + - ! ~ ++x --x (T)x+ - ! ~ ++x --x (T)x
Operatori aritmeticiArithmetic operators MoltiplicazioneMultiplicative * / %* / %
Operatori aritmeticiArithmetic operators AddizioneAdditive + -+ -
Operatori shiftShift operators ShiftShift << >><< >>
Operatori relazionali e di test del tipoRelational and type-testing operators Operatori relazionali e operatori di test del tipoRelational and type testing < > <= >= is as< > <= >= is as
Operatori relazionali e di test del tipoRelational and type-testing operators UguaglianzaEquality == !=== !=
Operatori logiciLogical operators AND logicoLogical AND &
Operatori logiciLogical operators XOR logicoLogical XOR ^
Operatori logiciLogical operators OR logicoLogical OR |
Operatori logici condizionaliConditional logical operators AND condizionaleConditional AND &&
Operatori logici condizionaliConditional logical operators OR condizionaleConditional OR ||
Operatore null-coalescingThe null coalescing operator Null-coalescingNull coalescing ??
Operatore condizionaleConditional operator AccessoConditional ?:
Operatori di assegnazione, espressioni di funzioni anonimeAssignment operators, Anonymous function expressions Assegnazione ed espressione lambdaAssignment and lambda expression = *= /= %= += -= <<= >>= &= ^= |= =>= *= /= %= += -= <<= >>= &= ^= |= =>

Quando si verifica un operando tra due operatori con la stessa precedenza, l'associatività degli operatori controlla l'ordine in cui vengono eseguite le operazioni: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:

  • Ad eccezione degli operatori di assegnazione e dell'operatore di Unione null, tutti gli operatori binari sono associativi a sinistra, ovvero le operazioni vengono eseguite da sinistra a destra.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. L'espressione x + y + z viene ad esempio valutata come (x + y) + z.For example, x + y + z is evaluated as (x + y) + z.
  • Gli operatori di assegnazione, l'operatore di Unione null e l'operatore condizionale (?:) sono associativi a destra, ovvero le operazioni vengono eseguite da destra a sinistra.The assignment operators, the null coalescing operator and the conditional operator (?:) are right-associative, meaning that operations are performed from right to left. L'espressione x = y = z viene ad esempio valutata come x = (y = z).For example, x = y = z is evaluated as x = (y = z).

È possibile controllare la precedenza e l'associatività usando le parentesi.Precedence and associativity can be controlled using parentheses. Ad esempio, x + y * z prima moltiplica y per z e quindi somma il risultato a x, ma (x + y) * z prima somma x e y e quindi moltiplica il risultato per 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.

Overload degli operatoriOperator overloading

Tutti gli operatori unari e binari hanno implementazioni predefinite che sono automaticamente disponibili in qualsiasi espressione.All unary and binary operators have predefined implementations that are automatically available in any expression. Oltre alle implementazioni predefinite, le implementazioni definite dall'utente possono essere introdotte includendo operator dichiarazioni nelle classi e negli struct (operatori).In addition to the predefined implementations, user-defined implementations can be introduced by including operator declarations in classes and structs (Operators). Le implementazioni degli operatori definite dall'utente hanno sempre la precedenza sulle implementazioni di operatori predefinite: solo quando non esistono implementazioni di operatori definite dall'utente applicabili, verranno considerate le implementazioni degli operatori predefinite, come descritto in risoluzione dell'overload dell'operatore unario e risoluzione dell'overload dell'operatore binario.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.

Gli operatori unari che eseguono l'overload sono:The overloadable unary operators are:

+   -   !   ~   ++   --   true   false

Anche se true e false non vengono utilizzati in modo esplicito nelle espressioni (e pertanto non sono inclusi nella tabella di precedenza in precedenza e associativitàdegli operatori), sono considerati operatori perché vengono richiamati in diversi contesti di espressione: espressioni booleane (espressioni booleane) ed espressioni che interessano l'operatore condizionale (operatore condizionale) e glioperatori logicicondizionaliAlthough 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).

Gli operatori binari che eseguono l'overload sono:The overloadable binary operators are:

+   -   *   /   %   &   |   ^   <<   >>   ==   !=   >   <   >=   <=

È possibile eseguire l'overload solo degli operatori elencati in precedenza.Only the operators listed above can be overloaded. In particolare, non è possibile eseguire l'overload dell'accesso ai membri, della chiamata al metodo o degli operatori =, &&, ||, ??, ?:, =>, checked, unchecked, new, typeof, default, ase is.In particular, it is not possible to overload member access, method invocation, or the =, &&, ||, ??, ?:, =>, checked, unchecked, new, typeof, default, as, and is operators.

Quando viene eseguito l'overload di un operatore binario, viene anche eseguito in modo implicito l'overload dell'operatore di assegnazione corrispondente, se presente.When a binary operator is overloaded, the corresponding assignment operator, if any, is also implicitly overloaded. Un overload dell'operatore *, ad esempio, è anche un overload dell'operatore *=.For example, an overload of operator * is also an overload of operator *=. Questa operazione viene descritta ulteriormente nell' assegnazione composta.This is described further in Compound assignment. Si noti che non è possibile eseguire l'overload dell'operatore di assegnazione (=).Note that the assignment operator itself (=) cannot be overloaded. Un'assegnazione esegue sempre una semplice copia bit di un valore in una variabile.An assignment always performs a simple bit-wise copy of a value into a variable.

Le operazioni cast, ad esempio (T)x, vengono sottocaricate fornendo conversioni definite dall'utente (conversioni definite dall'utente).Cast operations, such as (T)x, are overloaded by providing user-defined conversions (User-defined conversions).

L'accesso agli elementi, ad esempio a[x], non è considerato un operatore che può eseguire l'overload.Element access, such as a[x], is not considered an overloadable operator. L'indicizzazione definita dall'utente è invece supportata tramite gli indicizzatori (indicizzatori).Instead, user-defined indexing is supported through indexers (Indexers).

Nelle espressioni viene fatto riferimento agli operatori usando la notazione dell'operatore e, nelle dichiarazioni, viene fatto riferimento agli operatori usando la notazione funzionale.In expressions, operators are referenced using operator notation, and in declarations, operators are referenced using functional notation. Nella tabella seguente viene illustrata la relazione tra operatore e notazioni funzionali per gli operatori unari e binari.The following table shows the relationship between operator and functional notations for unary and binary operators. Nella prima voce, op denota qualsiasi operatore di prefisso unario che è in overload.In the first entry, op denotes any overloadable unary prefix operator. Nella seconda voce, op indica il suffisso unario ++ e gli operatori --.In the second entry, op denotes the unary postfix ++ and -- operators. Nella terza voce, op denota qualsiasi operatore binario di overload.In the third entry, op denotes any overloadable binary operator.

Notazione operatoreOperator notation Notazione funzionaleFunctional notation
op x operator op(x)
x op operator op(x)
x op y operator op(x,y)

Per le dichiarazioni di operatore definite dall'utente è sempre necessario che almeno uno dei parametri sia del tipo di classe o struct che contiene la dichiarazione di operatore.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. Non è quindi possibile che un operatore definito dall'utente abbia la stessa firma di un operatore predefinito.Thus, it is not possible for a user-defined operator to have the same signature as a predefined operator.

Le dichiarazioni di operatore definite dall'utente non possono modificare la sintassi, la precedenza o l'associatività di un operatore.User-defined operator declarations cannot modify the syntax, precedence, or associativity of an operator. Ad esempio, l'operatore / è sempre un operatore binario, ha sempre il livello di precedenza specificato in precedenza e associatività degli operatoried è sempre associato a sinistra.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.

Sebbene sia possibile che un operatore definito dall'utente esegua qualsiasi calcolo, le implementazioni che producono risultati diversi da quelli previsti in modo intuitivo sono fortemente sconsigliate.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. Ad esempio, un'implementazione di operator == deve confrontare i due operandi per verificarne l'uguaglianza e restituire un risultato bool appropriato.For example, an implementation of operator == should compare the two operands for equality and return an appropriate bool result.

Le descrizioni dei singoli operatori nelle espressioni primarie tramite gli operatori logici condizionali specificano le implementazioni predefinite degli operatori ed eventuali regole aggiuntive che si applicano a ogni operatore.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. Le descrizioni utilizzano i termini risoluzione dell' Overload dell'operatore unario, risoluzione dell'overload degli operatori binarie innalzamentodi livello numerico, le cui definizioni sono disponibili nelle sezioni riportate di seguito.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.

Risoluzione dell'overload dell'operatore unarioUnary operator overload resolution

Un'operazione nel formato op x o x op, in cui op è un operatore unario che esegue l'overload e x è un'espressione di tipo X, viene elaborata come segue: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:

  • Il set di operatori definiti dall'utente candidati fornito da X per l'operazione operator op(x) viene determinato mediante le regole degli operatori candidati definiti dall'utente.The set of candidate user-defined operators provided by X for the operation operator op(x) is determined using the rules of Candidate user-defined operators.
  • Se il set di operatori definiti dall'utente candidato non è vuoto, diventa il set di operatori candidati per l'operazione.If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. In caso contrario, le implementazioni di operator op unario predefinite, inclusi i moduli rimossi, diventano il set di operatori candidati per l'operazione.Otherwise, the predefined unary operator op implementations, including their lifted forms, become the set of candidate operators for the operation. Le implementazioni predefinite di un determinato operatore vengono specificate nella descrizione dell'operatore (espressioni primarie e operatori unari).The predefined implementations of a given operator are specified in the description of the operator (Primary expressions and Unary operators).
  • Le regole di risoluzione dell'overload della risoluzione dell'overload vengono applicate al set di operatori candidati per selezionare l'operatore migliore rispetto all'elenco di argomenti (x)e questo operatore diventa il risultato del processo di risoluzione dell'overload.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. Se la risoluzione dell'overload non riesce a selezionare un singolo operatore migliore, si verifica un errore in fase di binding.If overload resolution fails to select a single best operator, a binding-time error occurs.

Risoluzione dell'overload dell'operatore binarioBinary operator overload resolution

Un'operazione nel formato x op y, dove op è un operatore binario che può essere sottoposto a overload, x è un'espressione di tipo Xe y è un'espressione di tipo Y, viene elaborata come indicato di seguito: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:

  • Viene determinato il set di operatori candidati definiti dall'utente forniti da X e Y per l'operazione operator op(x,y).The set of candidate user-defined operators provided by X and Y for the operation operator op(x,y) is determined. Il set è costituito dall'Unione degli operatori candidati forniti da X e dagli operatori candidati forniti da Y, ciascuno dei quali viene determinato mediante le regole degli operatori candidati definiti dall'utente.The set consists of the union of the candidate operators provided by X and the candidate operators provided by Y, each determined using the rules of Candidate user-defined operators. Se X e Y sono dello stesso tipo o se X e Y derivano da un tipo di base comune, gli operatori candidati condivisi vengono eseguiti solo una volta nel set combinato.If X and Y are the same type, or if X and Y are derived from a common base type, then shared candidate operators only occur in the combined set once.
  • Se il set di operatori definiti dall'utente candidato non è vuoto, diventa il set di operatori candidati per l'operazione.If the set of candidate user-defined operators is not empty, then this becomes the set of candidate operators for the operation. In caso contrario, le implementazioni binarie operator op predefinite, inclusi i moduli rimossi, diventano il set di operatori candidati per l'operazione.Otherwise, the predefined binary operator op implementations, including their lifted forms, become the set of candidate operators for the operation. Le implementazioni predefinite di un determinato operatore vengono specificate nella descrizione dell'operatore (operatori aritmetici tramite operatori logici condizionali).The predefined implementations of a given operator are specified in the description of the operator (Arithmetic operators through Conditional logical operators). Per gli operatori enum e Delegate predefiniti, gli unici operatori considerati sono quelli definiti da un tipo enum o delegate che rappresenta il tipo in fase di binding di uno degli operandi.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.
  • Le regole di risoluzione dell'overload della risoluzione dell'overload vengono applicate al set di operatori candidati per selezionare l'operatore migliore rispetto all'elenco di argomenti (x,y)e questo operatore diventa il risultato del processo di risoluzione dell'overload.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. Se la risoluzione dell'overload non riesce a selezionare un singolo operatore migliore, si verifica un errore in fase di binding.If overload resolution fails to select a single best operator, a binding-time error occurs.

Operatori definiti dall'utente candidatiCandidate user-defined operators

Dato un tipo T e un'operazione operator op(A), dove op è un operatore che esegue l'overload e A è un elenco di argomenti, il set di operatori candidati definiti dall'utente fornito da T per operator op(A) viene determinato nel modo seguente: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:

  • Determinare il tipo T0.Determine the type T0. Se T è un tipo nullable, T0 è il tipo sottostante, in caso contrario T0 è uguale a T.If T is a nullable type, T0 is its underlying type, otherwise T0 is equal to T.
  • Per tutte le dichiarazioni di operator op in T0 e in tutte le forme elevate di tali operatori, se almeno un operatore è applicabile (membro della funzione applicabile) rispetto all'elenco di argomenti A, il set di operatori candidati è costituito da tutti gli operatori applicabili in T0.For all operator op declarations in T0 and all lifted forms of such operators, if at least one operator is applicable (Applicable function member) with respect to the argument list A, then the set of candidate operators consists of all such applicable operators in T0.
  • In caso contrario, se T0 è object, il set di operatori candidati è vuoto.Otherwise, if T0 is object, the set of candidate operators is empty.
  • In caso contrario, il set di operatori candidati fornito da T0 è il set di operatori candidati fornito dalla classe di base diretta di T0o la classe di base effettiva di T0 se T0 è un parametro di tipo.Otherwise, the set of candidate operators provided by T0 is the set of candidate operators provided by the direct base class of T0, or the effective base class of T0 if T0 is a type parameter.

Promozioni numericheNumeric promotions

La promozione numerica è costituita dall'esecuzione automatica di alcune conversioni implicite degli operandi degli operatori numerici unari e binari predefiniti.Numeric promotion consists of automatically performing certain implicit conversions of the operands of the predefined unary and binary numeric operators. La promozione numerica non è un meccanismo distinto, bensì un effetto dell'applicazione della risoluzione dell'overload agli operatori predefiniti.Numeric promotion is not a distinct mechanism, but rather an effect of applying overload resolution to the predefined operators. La promozione numerica non influisce specificamente sulla valutazione degli operatori definiti dall'utente, anche se gli operatori definiti dall'utente possono essere implementati in modo da presentare effetti simili.Numeric promotion specifically does not affect evaluation of user-defined operators, although user-defined operators can be implemented to exhibit similar effects.

Come esempio di promozione numerica, prendere in considerazione le implementazioni predefinite dell'operatore Binary *: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);

Quando vengono applicate regole di risoluzione dell'overload (risoluzione dell'overload) a questo set di operatori, l'effetto è quello di selezionare il primo degli operatori per cui esistono conversioni implicite dai tipi di operando.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. Ad esempio, per l'operazione b * s, dove b è un byte e s è un short, la risoluzione dell'overload seleziona operator *(int,int) come operatore migliore.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. Pertanto, l'effetto è che b e s vengono convertiti in inte il tipo del risultato è int.Thus, the effect is that b and s are converted to int, and the type of the result is int. Analogamente, per l'operazione i * d, dove i è un int e d è un double, la risoluzione dell'overload seleziona operator *(double,double) come operatore migliore.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.

Promozioni numeriche unarieUnary numeric promotions

La promozione numerica unaria si verifica per gli operandi degli operatori unari +, -e ~ predefiniti.Unary numeric promotion occurs for the operands of the predefined +, -, and ~ unary operators. La promozione numerica unaria consiste semplicemente nella conversione di operandi di tipo sbyte, byte, short, ushorto char nel tipo int.Unary numeric promotion simply consists of converting operands of type sbyte, byte, short, ushort, or char to type int. Inoltre, per l'operatore unario -, la promozione numerica unaria converte gli operandi di tipo uint nel tipo long.Additionally, for the unary - operator, unary numeric promotion converts operands of type uint to type long.

Promozioni numeriche binarieBinary numeric promotions

La promozione numerica binaria viene eseguita per gli operandi degli operatori binari +, -, *, /, %, &, |, ^, ==, !=, >, <, >=e <= specificati.Binary numeric promotion occurs for the operands of the predefined +, -, *, /, %, &, |, ^, ==, !=, >, <, >=, and <= binary operators. L'innalzamento di livello numerico binario converte in modo implicito entrambi gli operandi in un tipo comune, che, nel caso degli operatori non relazionali, diventa anche il tipo di risultato dell'operazione.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. L'innalzamento di numero binario consiste nell'applicare le regole seguenti, nell'ordine in cui sono visualizzate:Binary numeric promotion consists of applying the following rules, in the order they appear here:

  • Se uno degli operandi è di tipo decimal, l'altro operando viene convertito nel tipo decimaloppure si verifica un errore in fase di binding se l'altro operando è di tipo float o double.If either operand is of type decimal, the other operand is converted to type decimal, or a binding-time error occurs if the other operand is of type float or double.
  • In caso contrario, se uno degli operandi è di tipo double, l'altro operando verrà convertito nel tipo double.Otherwise, if either operand is of type double, the other operand is converted to type double.
  • In caso contrario, se uno degli operandi è di tipo float, l'altro operando verrà convertito nel tipo float.Otherwise, if either operand is of type float, the other operand is converted to type float.
  • In caso contrario, se uno degli operandi è di tipo ulong, l'altro operando viene convertito nel tipo ulongoppure si verifica un errore in fase di binding se l'altro operando è di tipo sbyte, short, into long.Otherwise, if either operand is of type ulong, the other operand is converted to type ulong, or a binding-time error occurs if the other operand is of type sbyte, short, int, or long.
  • In caso contrario, se uno degli operandi è di tipo long, l'altro operando verrà convertito nel tipo long.Otherwise, if either operand is of type long, the other operand is converted to type long.
  • In caso contrario, se uno degli operandi è di tipo uint e l'altro operando è di tipo sbyte, shorto int, entrambi gli operandi vengono convertiti nel tipo long.Otherwise, if either operand is of type uint and the other operand is of type sbyte, short, or int, both operands are converted to type long.
  • In caso contrario, se uno degli operandi è di tipo uint, l'altro operando verrà convertito nel tipo uint.Otherwise, if either operand is of type uint, the other operand is converted to type uint.
  • In caso contrario, entrambi gli operandi vengono convertiti nel tipo int.Otherwise, both operands are converted to type int.

Si noti che la prima regola impedisce qualsiasi operazione che combina il tipo di decimal con i tipi di double e float.Note that the first rule disallows any operations that mix the decimal type with the double and float types. La regola segue dal fatto che non esistono conversioni implicite tra il tipo di decimal e i tipi di double e float.The rule follows from the fact that there are no implicit conversions between the decimal type and the double and float types.

Si noti inoltre che non è possibile che un operando sia di tipo ulong quando l'altro operando è di un tipo integrale con segno.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. Il motivo è che non esiste alcun tipo integrale che può rappresentare l'intera gamma di ulong e i tipi integrali con segno.The reason is that no integral type exists that can represent the full range of ulong as well as the signed integral types.

In entrambi i casi precedenti, è possibile usare un'espressione cast per convertire in modo esplicito un operando in un tipo compatibile con l'altro operando.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.

Nell'esempioIn the example

decimal AddPercent(decimal x, double percent) {
    return x * (1.0 + percent / 100.0);
}

si verifica un errore in fase di binding perché un decimal non può essere moltiplicato per un double.a binding-time error occurs because a decimal cannot be multiplied by a double. L'errore viene risolto convertendo in modo esplicito il secondo operando in decimal, come indicato di seguito: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);
}

Operatori rimossiLifted operators

Gli operatori rimossi consentono agli operatori predefiniti e definiti dall'utente che operano su tipi di valore non nullable di essere utilizzati anche con forme Nullable di tali tipi.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. Gli operatori rimossi vengono costruiti da operatori predefiniti e definiti dall'utente che soddisfano determinati requisiti, come descritto di seguito:Lifted operators are constructed from predefined and user-defined operators that meet certain requirements, as described in the following:

  • Per gli operatori unariFor the unary operators

    +  ++  -  --  !  ~
    

    un modulo elevato di un operatore esiste se i tipi di operando e di risultato sono entrambi tipi di valore non nullable.a lifted form of an operator exists if the operand and result types are both non-nullable value types. Il form elevato viene costruito aggiungendo un singolo modificatore ? all'operando e ai tipi di risultato.The lifted form is constructed by adding a single ? modifier to the operand and result types. L'operatore lifted produce un valore null se l'operando è null.The lifted operator produces a null value if the operand is null. In caso contrario, l'operatore lifted Elimina il wrapping dell'operando, applica l'operatore sottostante ed esegue il wrapping del risultato.Otherwise, the lifted operator unwraps the operand, applies the underlying operator, and wraps the result.

  • Per gli operatori binariFor the binary operators

    +  -  *  /  %  &  |  ^  <<  >>
    

    Se l'operando e i tipi di risultato sono tutti tipi di valore non nullable, è presente una forma Lifted di un operatore.a lifted form of an operator exists if the operand and result types are all non-nullable value types. Il form elevato viene costruito aggiungendo un singolo modificatore ? a ogni operando e tipo di risultato.The lifted form is constructed by adding a single ? modifier to each operand and result type. L'operatore lifted produce un valore null se uno o entrambi gli operandi sono null (un'eccezione è costituita dagli operatori & e | del tipo bool?, come descritto in operatori logici booleani).The lifted operator produces a null value if one or both operands are null (an exception being the & and | operators of the bool? type, as described in Boolean logical operators). In caso contrario, l'operatore lifted esegue l'unwrapping degli operandi, applica l'operatore sottostante ed esegue il wrapping del risultato.Otherwise, the lifted operator unwraps the operands, applies the underlying operator, and wraps the result.

  • Per gli operatori di uguaglianzaFor the equality operators

    ==  !=
    

    un modulo Lifted di un operatore esiste se i tipi di operando sono entrambi tipi di valore non nullable e se il tipo di risultato è bool.a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type is bool. Il form elevato viene costruito aggiungendo un singolo modificatore ? a ogni tipo di operando.The lifted form is constructed by adding a single ? modifier to each operand type. L'operatore lifted considera due valori null uguali e un valore null diverso da un valore diverso da null.The lifted operator considers two null values equal, and a null value unequal to any non-null value. Se entrambi gli operandi sono non null, l'operatore lifted Annulla il wrapping degli operandi e applica l'operatore sottostante per produrre il risultato della bool.If both operands are non-null, the lifted operator unwraps the operands and applies the underlying operator to produce the bool result.

  • Per gli operatori relazionaliFor the relational operators

    <  >  <=  >=
    

    un modulo Lifted di un operatore esiste se i tipi di operando sono entrambi tipi di valore non nullable e se il tipo di risultato è bool.a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type is bool. Il form elevato viene costruito aggiungendo un singolo modificatore ? a ogni tipo di operando.The lifted form is constructed by adding a single ? modifier to each operand type. L'operatore lifted produce il valore false se uno o entrambi gli operandi sono null.The lifted operator produces the value false if one or both operands are null. In caso contrario, l'operatore lifted esegue l'unwrapping degli operandi e applica l'operatore sottostante per produrre il risultato della bool.Otherwise, the lifted operator unwraps the operands and applies the underlying operator to produce the bool result.

Ricerca di membriMember lookup

Una ricerca di membri è il processo in base al quale viene determinato il significato di un nome nel contesto di un tipo.A member lookup is the process whereby the meaning of a name in the context of a type is determined. Una ricerca di membri può essere eseguita come parte della valutazione di un simple_name (nomi semplici) o di un member_access (accesso ai membri) in un'espressione.A member lookup can occur as part of evaluating a simple_name (Simple names) or a member_access (Member access) in an expression. Se il simple_name o member_access si verifica come primary_expression di un invocation_expression (chiamate al metodo), viene detto che il membro viene richiamato.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.

Se un membro è un metodo o un evento o se è una costante, un campo o una proprietà di un tipo delegato (delegati) o del tipo dynamic (il tipo dinamico), il membro viene definito richiamabile.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.

La ricerca di membri considera non solo il nome di un membro, ma anche il numero di parametri di tipo del membro e se il membro è accessibile.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. Ai fini della ricerca dei membri, i metodi generici e i tipi generici annidati hanno il numero di parametri di tipo indicati nelle rispettive dichiarazioni e tutti gli altri membri hanno zero parametri di tipo.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.

Una ricerca di membri di un nome N con Kparametri di tipo  in un tipo T viene elaborata come segue:A member lookup of a name N with K type parameters in a type T is processed as follows:

  • In primo luogo, viene determinato un set di membri accessibili denominato N:First, a set of accessible members named N is determined:
    • Se T è un parametro di tipo, il set è l'Unione dei set di membri accessibili denominati N in ognuno dei tipi specificati come vincolo primario o secondario (vincoli diparametro di tipo) per T, insieme al set di membri accessibili denominato N in object.If T is a type parameter, then the set is the union of the sets of accessible members named N in each of the types specified as a primary constraint or secondary constraint (Type parameter constraints) for T, along with the set of accessible members named N in object.
    • In caso contrario, il set è costituito da tutti i membri accessibili (accesso ai membri) denominati N in T, inclusi i membri ereditati e i membri accessibili denominati N in object.Otherwise, the set consists of all accessible (Member access) members named N in T, including inherited members and the accessible members named N in object. Se T è un tipo costruito, il set di membri viene ottenuto sostituendo gli argomenti di tipo come descritto in membri dei tipi costruiti.If T is a constructed type, the set of members is obtained by substituting type arguments as described in Members of constructed types. I membri che includono un modificatore override vengono esclusi dal set.Members that include an override modifier are excluded from the set.
  • Se quindi K è zero, tutti i tipi annidati le cui dichiarazioni includono parametri di tipo vengono rimossi.Next, if K is zero, all nested types whose declarations include type parameters are removed. Se K è diverso da zero, vengono rimossi tutti i membri con un numero diverso di parametri di tipo.If K is not zero, all members with a different number of type parameters are removed. Si noti che quando K è zero, i metodi con parametri di tipo non vengono rimossi, perché il processo di inferenza del tipo (inferenzadel tipo) potrebbe essere in grado di dedurre gli argomenti di tipo.Note that when K is zero, methods having type parameters are not removed, since the type inference process (Type inference) might be able to infer the type arguments.
  • Successivamente, se il membro viene richiamato, tutti i membri nonrichiamabile vengono rimossi dal set.Next, if the member is invoked, all non-invocable members are removed from the set.
  • Successivamente, i membri che sono nascosti da altri membri vengono rimossi dal set.Next, members that are hidden by other members are removed from the set. Per ogni membro S.M nel set, dove S è il tipo in cui viene dichiarata la M membro, vengono applicate le regole seguenti:For every member S.M in the set, where S is the type in which the member M is declared, the following rules are applied:
    • Se M è una costante, un campo, una proprietà, un evento o un membro di enumerazione, tutti i membri dichiarati in un tipo di base di S vengono rimossi dal set.If M is a constant, field, property, event, or enumeration member, then all members declared in a base type of S are removed from the set.
    • Se M è una dichiarazione di tipo, tutti i tipi non dichiarati in un tipo di base di S vengono rimossi dal set e tutte le dichiarazioni di tipo con lo stesso numero di parametri di tipo M dichiarati in un tipo di base di S vengono rimosse dal set.If M is a type declaration, then all non-types declared in a base type of S are removed from the set, and all type declarations with the same number of type parameters as M declared in a base type of S are removed from the set.
    • Se M è un metodo, tutti i membri non del metodo dichiarati in un tipo di base di S vengono rimossi dal set.If M is a method, then all non-method members declared in a base type of S are removed from the set.
  • Quindi, i membri di interfaccia nascosti dai membri della classe vengono rimossi dal set.Next, interface members that are hidden by class members are removed from the set. Questo passaggio ha effetto solo se T è un parametro di tipo e T dispone di una classe di base efficace diversa da object e di un set di interfacce effettivo non vuoto (vincoli del parametro di tipo).This step only has an effect if T is a type parameter and T has both an effective base class other than object and a non-empty effective interface set (Type parameter constraints). Per ogni membro S.M nel set, dove S è il tipo in cui viene dichiarata la M membro, vengono applicate le regole seguenti se S è una dichiarazione di classe diversa da object:For every member S.M in the set, where S is the type in which the member M is declared, the following rules are applied if S is a class declaration other than object:
    • Se M è una costante, un campo, una proprietà, un evento, un membro di enumerazione o una dichiarazione di tipo, tutti i membri dichiarati in una dichiarazione di interfaccia vengono rimossi dal set.If M is a constant, field, property, event, enumeration member, or type declaration, then all members declared in an interface declaration are removed from the set.
    • Se M è un metodo, tutti i membri non di metodo dichiarati in una dichiarazione di interfaccia vengono rimossi dal set e tutti i metodi con la stessa firma M dichiarati in una dichiarazione di interfaccia vengono rimossi dal set.If M 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 as M declared in an interface declaration are removed from the set.
  • Infine, dopo aver rimosso i membri nascosti, viene determinato il risultato della ricerca:Finally, having removed hidden members, the result of the lookup is determined:
    • Se il set è costituito da un singolo membro che non è un metodo, questo membro è il risultato della ricerca.If the set consists of a single member that is not a method, then this member is the result of the lookup.
    • In caso contrario, se il set contiene solo metodi, questo gruppo di metodi è il risultato della ricerca.Otherwise, if the set contains only methods, then this group of methods is the result of the lookup.
    • In caso contrario, la ricerca è ambigua e si verifica un errore in fase di binding.Otherwise, the lookup is ambiguous, and a binding-time error occurs.

Per le ricerche di membri in tipi diversi da parametri e interfacce di tipo e ricerche di membri in interfacce che sono esclusivamente a ereditarietà singola (ogni interfaccia nella catena di ereditarietà ha esattamente zero o un'interfaccia di base diretta), l'effetto delle regole di ricerca è semplicemente i membri derivati nascondono i membri di base con lo stesso nome o la stessa firma.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. Queste ricerche con ereditarietà singola non sono mai ambigue.Such single-inheritance lookups are never ambiguous. Le ambiguità che possono derivare da ricerche di membri nelle interfacce con ereditarietà multipla sono descritte in accesso ai membri di interfaccia.The ambiguities that can possibly arise from member lookups in multiple-inheritance interfaces are described in Interface member access.

Tipi di baseBase types

Ai fini della ricerca dei membri, un tipo T viene considerato con i tipi di base seguenti:For purposes of member lookup, a type T is considered to have the following base types:

  • Se T è object, T non ha alcun tipo di base.If T is object, then T has no base type.
  • Se T è un enum_type, i tipi di base di T sono i tipi di classe System.Enum, System.ValueTypee object.If T is an enum_type, the base types of T are the class types System.Enum, System.ValueType, and object.
  • Se T è un struct_type, i tipi di base di T sono i tipi di classe System.ValueType e object.If T is a struct_type, the base types of T are the class types System.ValueType and object.
  • Se T è un class_type, i tipi di base di T sono le classi di base di T, incluso il tipo di classe object.If T is a class_type, the base types of T are the base classes of T, including the class type object.
  • Se T è un INTERFACE_TYPE, i tipi di base di T sono le interfacce di base di T e il tipo di classe object.If T is an interface_type, the base types of T are the base interfaces of T and the class type object.
  • Se T è un array_type, i tipi di base di T sono i tipi di classe System.Array e object.If T is an array_type, the base types of T are the class types System.Array and object.
  • Se T è un delegate_type, i tipi di base di T sono i tipi di classe System.Delegate e object.If T is a delegate_type, the base types of T are the class types System.Delegate and object.

Membri di funzioneFunction members

I membri di funzione sono membri che contengono istruzioni eseguibili.Function members are members that contain executable statements. I membri di funzione sono sempre membri di tipi e non possono essere membri di spazi dei nomi.Function members are always members of types and cannot be members of namespaces. C#definisce le categorie seguenti di membri di funzione:C# defines the following categories of function members:

  • MetodiMethods
  • ProprietàProperties
  • EventsEvents
  • Indexers (Indicizzatori)Indexers
  • Operatori definiti dall'utenteUser-defined operators
  • Costruttori di istanzeInstance constructors
  • Costruttori staticiStatic constructors
  • DistruttoriDestructors

Ad eccezione dei distruttori e dei costruttori statici (che non possono essere richiamati in modo esplicito), le istruzioni contenute nei membri della funzione vengono eseguite tramite chiamate di membri di funzione.Except for destructors and static constructors (which cannot be invoked explicitly), the statements contained in function members are executed through function member invocations. La sintassi effettiva per la scrittura di una chiamata di membro di funzione dipende dalla categoria di membri della funzione specifica.The actual syntax for writing a function member invocation depends on the particular function member category.

L'elenco di argomenti (elenchi di argomenti) della chiamata di un membro di funzione fornisce valori effettivi o riferimenti a variabili per i parametri del membro della funzione.The argument list (Argument lists) of a function member invocation provides actual values or variable references for the parameters of the function member.

Le chiamate dei metodi generici possono utilizzare l'inferenza del tipo per determinare il set di argomenti di tipo da passare al metodo.Invocations of generic methods may employ type inference to determine the set of type arguments to pass to the method. Questo processo è descritto in inferenza del tipo.This process is described in Type inference.

Le chiamate di metodi, indicizzatori, operatori e costruttori di istanza utilizzano la risoluzione dell'overload per determinare quale di un set candidato di membri di funzione richiamare.Invocations of methods, indexers, operators and instance constructors employ overload resolution to determine which of a candidate set of function members to invoke. Questo processo è descritto in risoluzione dell'overload.This process is described in Overload resolution.

Una volta identificato un particolare membro di funzione in fase di binding, eventualmente tramite la risoluzione dell'overload, il processo di runtime effettivo per richiamare il membro della funzione viene descritto in fase di compilazione controllo della risoluzione dell'overload dinamico.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.

Nella tabella seguente viene riepilogata l'elaborazione che si verifica nei costrutti che coinvolgono le sei categorie di membri di funzione che possono essere richiamate in modo esplicito.The following table summarizes the processing that takes place in constructs involving the six categories of function members that can be explicitly invoked. Nella tabella e, x, ye value indicano espressioni classificate come variabili o valori, T indica un'espressione classificata come tipo, F è il nome semplice di un metodo e P è il nome semplice di una proprietà.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.

CostruireConstruct EsempioExample DescrizioneDescription
Chiamata del metodoMethod invocation F(x,y) Viene applicata la risoluzione dell'overload per selezionare il metodo migliore F nella classe o nello struct contenitore.Overload resolution is applied to select the best method F in the containing class or struct. Il metodo viene richiamato con l'elenco di argomenti (x,y).The method is invoked with the argument list (x,y). Se il metodo non è static, l'espressione dell'istanza è this.If the method is not static, the instance expression is this.
T.F(x,y) Viene applicata la risoluzione dell'overload per selezionare il metodo migliore F nel Tdella classe o dello struct.Overload resolution is applied to select the best method F in the class or struct T. Se il metodo non è static, si verifica un errore in fase di binding.A binding-time error occurs if the method is not static. Il metodo viene richiamato con l'elenco di argomenti (x,y).The method is invoked with the argument list (x,y).
e.F(x,y) Viene applicata la risoluzione dell'overload per selezionare il miglior metodo F nella classe, nello struct o nell'interfaccia fornita dal tipo di e.Overload resolution is applied to select the best method F in the class, struct, or interface given by the type of e. Si verifica un errore in fase di binding se il metodo viene static.A binding-time error occurs if the method is static. Il metodo viene richiamato con l'espressione dell'istanza e e l'elenco di argomenti (x,y).The method is invoked with the instance expression e and the argument list (x,y).
Accesso a proprietàProperty access P Viene richiamata la funzione di accesso get della proprietà P nella classe o nello struct che lo contiene.The get accessor of the property P in the containing class or struct is invoked. Se P è di sola scrittura, si verifica un errore in fase di compilazione.A compile-time error occurs if P is write-only. Se P non è static, l'espressione di istanza viene thista.If P is not static, the instance expression is this.
P = value La funzione di accesso set della proprietà P nella classe o nello struct contenitore viene richiamata con l'elenco di argomenti (value).The set accessor of the property P in the containing class or struct is invoked with the argument list (value). Se P è di sola lettura, si verifica un errore in fase di compilazione.A compile-time error occurs if P is read-only. Se P non è static, l'espressione di istanza viene thista.If P is not static, the instance expression is this.
T.P Viene richiamata la funzione di accesso get della proprietà P nel T della classe o dello struct.The get accessor of the property P in the class or struct T is invoked. Si verifica un errore in fase di compilazione se P non è static o se P è di sola scrittura.A compile-time error occurs if P is not static or if P is write-only.
T.P = value La funzione di accesso set della proprietà P nel T della classe o dello struct viene richiamata con l'elenco di argomenti (value).The set accessor of the property P in the class or struct T is invoked with the argument list (value). Si verifica un errore in fase di compilazione se P non è static o se P è di sola lettura.A compile-time error occurs if P is not static or if P is read-only.
e.P La funzione di accesso get della proprietà P nella classe, nello struct o nell'interfaccia fornita dal tipo di e viene richiamata con l'espressione dell'istanza 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. Si verifica un errore in fase di binding se P è static o se P è di sola scrittura.A binding-time error occurs if P is static or if P is write-only.
e.P = value La funzione di accesso set della proprietà P nella classe, nello struct o nell'interfaccia fornita dal tipo di e viene richiamata con l'espressione dell'istanza e e l'elenco di argomenti (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). Si verifica un errore in fase di binding se P è static o se P è di sola lettura.A binding-time error occurs if P is static or if P is read-only.
Accesso agli eventiEvent access E += value Viene richiamata la funzione di accesso add dell'evento E nella classe o nello struct che lo contiene.The add accessor of the event E in the containing class or struct is invoked. Se E non è statico, l'espressione dell'istanza è this.If E is not static, the instance expression is this.
E -= value Viene richiamata la funzione di accesso remove dell'evento E nella classe o nello struct che lo contiene.The remove accessor of the event E in the containing class or struct is invoked. Se E non è statico, l'espressione dell'istanza è this.If E is not static, the instance expression is this.
T.E += value Viene richiamata la funzione di accesso add dell'evento E nella classe o nello struct T.The add accessor of the event E in the class or struct T is invoked. Si verifica un errore in fase di binding se E non è statico.A binding-time error occurs if E is not static.
T.E -= value Viene richiamata la funzione di accesso remove dell'evento E nella classe o nello struct T.The remove accessor of the event E in the class or struct T is invoked. Si verifica un errore in fase di binding se E non è statico.A binding-time error occurs if E is not static.
e.E += value La funzione di accesso add dell'evento E nella classe, nello struct o nell'interfaccia fornita dal tipo di e viene richiamata con l'espressione dell'istanza 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. Si verifica un errore in fase di binding se E è statico.A binding-time error occurs if E is static.
e.E -= value La funzione di accesso remove dell'evento E nella classe, nello struct o nell'interfaccia fornita dal tipo di e viene richiamata con l'espressione dell'istanza 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. Si verifica un errore in fase di binding se E è statico.A binding-time error occurs if E is static.
Accesso all'indicizzatoreIndexer access e[x,y] Viene applicata la risoluzione dell'overload per selezionare il migliore indicizzatore nella classe, nello struct o nell'interfaccia fornita dal tipo di e.Overload resolution is applied to select the best indexer in the class, struct, or interface given by the type of e. La funzione di accesso get dell'indicizzatore viene richiamata con l'espressione dell'istanza e e l'elenco di argomenti (x,y).The get accessor of the indexer is invoked with the instance expression e and the argument list (x,y). Si verifica un errore in fase di binding se l'indicizzatore è di sola scrittura.A binding-time error occurs if the indexer is write-only.
e[x,y] = value Viene applicata la risoluzione dell'overload per selezionare il migliore indicizzatore nella classe, nello struct o nell'interfaccia fornita dal tipo di e.Overload resolution is applied to select the best indexer in the class, struct, or interface given by the type of e. La funzione di accesso set dell'indicizzatore viene richiamata con l'espressione dell'istanza e e l'elenco di argomenti (x,y,value).The set accessor of the indexer is invoked with the instance expression e and the argument list (x,y,value). Si verifica un errore in fase di binding se l'indicizzatore è di sola lettura.A binding-time error occurs if the indexer is read-only.
Chiamata operatoreOperator invocation -x Viene applicata la risoluzione dell'overload per selezionare il migliore operatore unario nella classe o nello struct fornito dal tipo di x.Overload resolution is applied to select the best unary operator in the class or struct given by the type of x. L'operatore selezionato viene richiamato con l'elenco di argomenti (x).The selected operator is invoked with the argument list (x).
x + y Viene applicata la risoluzione dell'overload per selezionare l'operatore binario migliore nelle classi o negli struct specificati dai tipi di x e y.Overload resolution is applied to select the best binary operator in the classes or structs given by the types of x and y. L'operatore selezionato viene richiamato con l'elenco di argomenti (x,y).The selected operator is invoked with the argument list (x,y).
Chiamata del costruttore di istanzaInstance constructor invocation new T(x,y) Viene applicata la risoluzione dell'overload per selezionare il costruttore di istanze migliore nella classe o nello struct T.Overload resolution is applied to select the best instance constructor in the class or struct T. Il costruttore di istanza viene richiamato con l'elenco di argomenti (x,y).The instance constructor is invoked with the argument list (x,y).

Elenchi di argomentiArgument lists

Ogni membro della funzione e la chiamata al delegato includono un elenco di argomenti che fornisce valori effettivi o riferimenti a variabili per i parametri del membro della funzione.Every function member and delegate invocation includes an argument list which provides actual values or variable references for the parameters of the function member. La sintassi per specificare l'elenco di argomenti della chiamata di un membro di funzione dipende dalla categoria del membro della funzione:The syntax for specifying the argument list of a function member invocation depends on the function member category:

  • Per i costruttori di istanza, i metodi, gli indicizzatori e i delegati, gli argomenti vengono specificati come argument_list, come descritto di seguito.For instance constructors, methods, indexers and delegates, the arguments are specified as an argument_list, as described below. Per gli indicizzatori, quando si richiama la funzione di accesso set, l'elenco di argomenti include inoltre l'espressione specificata come operando destro dell'operatore di assegnazione.For indexers, when invoking the set accessor, the argument list additionally includes the expression specified as the right operand of the assignment operator.
  • Per le proprietà, l'elenco di argomenti è vuoto quando si richiama la funzione di accesso get ed è costituito dall'espressione specificata come operando destro dell'operatore di assegnazione quando si richiama la funzione di accesso set.For properties, the argument list is empty when invoking the get accessor, and consists of the expression specified as the right operand of the assignment operator when invoking the set accessor.
  • Per gli eventi, l'elenco di argomenti è costituito dall'espressione specificata come operando destro dell'operatore += o -=.For events, the argument list consists of the expression specified as the right operand of the += or -= operator.
  • Per gli operatori definiti dall'utente, l'elenco di argomenti è costituito dal singolo operando dell'operatore unario o dai due operandi dell'operatore binario.For user-defined operators, the argument list consists of the single operand of the unary operator or the two operands of the binary operator.

Gli argomenti delle proprietà (Proprietà), gli eventi (eventi) e gli operatori definiti dall'utente (operatori) vengono sempre passati come parametri valore (parametri valore).The arguments of properties (Properties), events (Events), and user-defined operators (Operators) are always passed as value parameters (Value parameters). Gli argomenti degli indicizzatori (indicizzatori) vengono sempre passati come parametri del valore (parametri di valore) o matrici di parametri (matricidi parametri).The arguments of indexers (Indexers) are always passed as value parameters (Value parameters) or parameter arrays (Parameter arrays). I parametri di riferimento e di output non sono supportati per queste categorie di membri di funzione.Reference and output parameters are not supported for these categories of function members.

Gli argomenti di un costruttore di istanza, un metodo, un indicizzatore o una chiamata a un delegato vengono specificati come 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
    ;

Un argument_list è costituito da uno o più argomenti, separati da virgole.An argument_list consists of one or more arguments, separated by commas. Ogni argomento è costituito da un argument_name facoltativo seguito da un argument_value.Each argument consists of an optional argument_name followed by an argument_value. Un argomento con un argument_name viene definito argomento denominato, mentre un argomento senza una argument_name è un argomento posizionale.An argument with an argument_name is referred to as a named argument, whereas an argument without an argument_name is a positional argument. Non è possibile visualizzare un argomento posizionale dopo un argomento denominato in un argument_list.It is an error for a positional argument to appear after a named argument in an argument_list.

Il argument_value può assumere uno dei seguenti formati:The argument_value can take one of the following forms:

  • Espressione, che indica che l'argomento viene passato come parametro del valore (parametri del valore).An expression, indicating that the argument is passed as a value parameter (Value parameters).
  • La parola chiave ref seguita da un variable_reference (riferimenti a variabili), che indica che l'argomento viene passato come parametro di riferimento (parametri diriferimento).The keyword ref followed by a variable_reference (Variable references), indicating that the argument is passed as a reference parameter (Reference parameters). Una variabile deve essere assegnata definitivamente (assegnazione definita) prima di poter essere passata come parametro di riferimento.A variable must be definitely assigned (Definite assignment) before it can be passed as a reference parameter. La parola chiave out seguita da un variable_reference (riferimenti a variabili), che indica che l'argomento viene passato come parametro di output (parametri dioutput).The keyword out followed by a variable_reference (Variable references), indicating that the argument is passed as an output parameter (Output parameters). Una variabile viene considerata definitivamente assegnata (assegnazione definita) dopo una chiamata del membro della funzione in cui la variabile viene passata come parametro di output.A variable is considered definitely assigned (Definite assignment) following a function member invocation in which the variable is passed as an output parameter.

Parametri corrispondentiCorresponding parameters

Per ogni argomento in un elenco di argomenti deve essere presente un parametro corrispondente nel membro della funzione o nel delegato richiamato.For each argument in an argument list there has to be a corresponding parameter in the function member or delegate being invoked.

L'elenco di parametri utilizzato nel codice seguente viene determinato nel modo seguente:The parameter list used in the following is determined as follows:

  • Per i metodi virtuali e gli indicizzatori definiti nelle classi, l'elenco di parametri viene selezionato dalla dichiarazione o dall'override più specifici del membro della funzione, a partire dal tipo statico del destinatario e dalla ricerca nelle relative classi di base.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.
  • Per i metodi di interfaccia e gli indicizzatori, l'elenco di parametri viene selezionato come la definizione più specifica del membro, a partire dal tipo di interfaccia e la ricerca nelle interfacce di base.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. Se non viene trovato alcun elenco di parametri univoco, viene creato un elenco di parametri con nomi inaccessibili senza parametri facoltativi, in modo che le chiamate non possano utilizzare parametri denominati o omettere argomenti facoltativi.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.
  • Per i metodi parziali, viene usato l'elenco di parametri della dichiarazione di metodo parziale di definizione.For partial methods, the parameter list of the defining partial method declaration is used.
  • Per tutti gli altri membri e delegati di funzioni è disponibile un solo elenco di parametri, ovvero quello usato.For all other function members and delegates there is only a single parameter list, which is the one used.

La posizione di un argomento o di un parametro è definita come numero di argomenti o parametri che lo precedono nell'elenco di argomenti o nell'elenco di parametri.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.

I parametri corrispondenti per gli argomenti del membro della funzione vengono definiti come segue:The corresponding parameters for function member arguments are established as follows:

  • Argomenti nel argument_list di costruttori di istanza, metodi, indicizzatori e delegati:Arguments in the argument_list of instance constructors, methods, indexers and delegates:
    • Un argomento posizionale in cui un parametro fisso si trova nella stessa posizione dell'elenco di parametri corrisponde al parametro.A positional argument where a fixed parameter occurs at the same position in the parameter list corresponds to that parameter.
    • Un argomento posizionale di un membro di funzione con una matrice di parametri richiamata nel formato normale corrisponde alla matrice di parametri, che deve essere presente nella stessa posizione dell'elenco dei parametri.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.
    • Un argomento posizionale di un membro di funzione con una matrice di parametri richiamata nel relativo form espanso, in cui nessun parametro fisso si trova nella stessa posizione nell'elenco di parametri, corrisponde a un elemento nella matrice di parametri.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.
    • Un argomento denominato corrisponde al parametro con lo stesso nome nell'elenco dei parametri.A named argument corresponds to the parameter of the same name in the parameter list.
    • Per gli indicizzatori, quando si richiama la funzione di accesso set, l'espressione specificata come operando di destra dell'operatore di assegnazione corrisponde al parametro value implicito della dichiarazione della funzione di accesso set.For indexers, when invoking the set accessor, the expression specified as the right operand of the assignment operator corresponds to the implicit value parameter of the set accessor declaration.
  • Per le proprietà, quando si richiama la funzione di accesso get non sono presenti argomenti.For properties, when invoking the get accessor there are no arguments. Quando si richiama la funzione di accesso set, l'espressione specificata come operando di destra dell'operatore di assegnazione corrisponde al parametro value implicito della dichiarazione della funzione di accesso set.When invoking the set accessor, the expression specified as the right operand of the assignment operator corresponds to the implicit value parameter of the set accessor declaration.
  • Per gli operatori unari definiti dall'utente (incluse le conversioni), il singolo operando corrisponde al singolo parametro della dichiarazione di operatore.For user-defined unary operators (including conversions), the single operand corresponds to the single parameter of the operator declaration.
  • Per gli operatori binari definiti dall'utente, l'operando sinistro corrisponde al primo parametro e l'operando destro corrisponde al secondo parametro della dichiarazione di operatore.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.

Valutazione in fase di esecuzione degli elenchi di argomentiRun-time evaluation of argument lists

Durante l'elaborazione in fase di esecuzione della chiamata di un membro di funzione (controllo in fase di compilazione della risoluzione dell'overload dinamico), le espressioni o i riferimenti alle variabili di un elenco di argomenti vengono valutati in ordine, da sinistra a destra, come indicato di seguito: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:

  • Per un parametro di valore, viene valutata l'espressione dell'argomento e viene eseguita una conversione implicita (conversioni implicite) nel tipo di parametro corrispondente.For a value parameter, the argument expression is evaluated and an implicit conversion (Implicit conversions) to the corresponding parameter type is performed. Il valore risultante diventa il valore iniziale del parametro value nella chiamata del membro della funzione.The resulting value becomes the initial value of the value parameter in the function member invocation.
  • Per un parametro di riferimento o di output, il riferimento alla variabile viene valutato e il percorso di archiviazione risultante diventa il percorso di archiviazione rappresentato dal parametro nella chiamata del membro della funzione.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. Se il riferimento a una variabile fornito come riferimento o parametro di output è un elemento di matrice di una reference_type, viene eseguito un controllo di runtime per garantire che il tipo di elemento della matrice sia identico al tipo del parametro.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. Se il controllo ha esito negativo, viene generata un'System.ArrayTypeMismatchException.If this check fails, a System.ArrayTypeMismatchException is thrown.

I metodi, gli indicizzatori e i costruttori di istanze possono dichiarare il parametro più a destra in modo che sia una matrice di parametri (matrici di parametri).Methods, indexers, and instance constructors may declare their right-most parameter to be a parameter array (Parameter arrays). Tali membri di funzione vengono richiamati nel formato normale o nel relativo form espanso a seconda del valore applicabile (membro della funzione applicabile):Such function members are invoked either in their normal form or in their expanded form depending on which is applicable (Applicable function member):

  • Quando un membro di funzione con una matrice di parametri viene richiamato nel formato normale, l'argomento specificato per la matrice di parametri deve essere una singola espressione convertibile in modo implicito (conversioni implicite) nel tipo di matrice di parametri.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 questo caso, la matrice di parametri funge esattamente da parametro di valore.In this case, the parameter array acts precisely like a value parameter.
  • Quando un membro di funzione con una matrice di parametri viene richiamato nella sua forma espansa, la chiamata deve specificare zero o più argomenti posizionali per la matrice di parametri, dove ogni argomento è un'espressione convertibile in modo implicito (conversioni implicite) nel tipo di elemento della matrice di parametri.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 questo caso, la chiamata crea un'istanza del tipo di matrice di parametri con una lunghezza corrispondente al numero di argomenti, inizializza gli elementi dell'istanza di matrice con i valori di argomento specificati e usa l'istanza di matrice appena creata come valore effettivo argomento.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.

Le espressioni di un elenco di argomenti vengono sempre valutate nell'ordine in cui vengono scritte.The expressions of an argument list are always evaluated in the order they are written. Quindi, l'esempioThus, 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++);
    }
}

produce l'outputproduces the output

x = 0, y = 1, z = 2
x = 4, y = -1, z = 3

Le regole di covarianza della matrice (covarianza di matrice) consentono un valore di un tipo di matrice A[] essere un riferimento a un'istanza di un tipo di matrice B[], purché esista una conversione implicita del riferimento da B a 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. A causa di queste regole, quando un elemento di matrice di un reference_type viene passato come parametro di riferimento o di output, è necessario un controllo Runtime per garantire che il tipo di elemento effettivo della matrice sia identico a quello del parametro.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. Nell'esempioIn 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
    }
}

la seconda chiamata di F causa la generazione di un System.ArrayTypeMismatchException perché il tipo di elemento effettivo di b è string e non 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.

Quando un membro di funzione con una matrice di parametri viene richiamato nella sua forma espansa, la chiamata viene elaborata esattamente come se fosse stata inserita un'espressione di creazione di matrice con un inizializzatore di matrice (espressioni di creazione di matrici) intorno ai parametri espansi.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. Ad esempio, in base alla dichiarazioneFor example, given the declaration

void F(int x, int y, params object[] args);

le chiamate seguenti della forma espansa del metodothe following invocations of the expanded form of the method

F(10, 20);
F(10, 20, 30, 40);
F(10, 20, 1, "hello", 3.0);

corrisponde esattamente acorrespond exactly to

F(10, 20, new object[] {});
F(10, 20, new object[] {30, 40});
F(10, 20, new object[] {1, "hello", 3.0});

In particolare, si noti che viene creata una matrice vuota quando sono presenti zero argomenti per la matrice di parametri.In particular, note that an empty array is created when there are zero arguments given for the parameter array.

Quando gli argomenti vengono omessi da un membro della funzione con i parametri facoltativi corrispondenti, gli argomenti predefiniti della dichiarazione del membro della funzione vengono passati in modo implicito.When arguments are omitted from a function member with corresponding optional parameters, the default arguments of the function member declaration are implicitly passed. Poiché questi sono sempre costanti, la valutazione non avrà alcun effetto sull'ordine di valutazione degli argomenti rimanenti.Because these are always constant, their evaluation will not impact the evaluation order of the remaining arguments.

Inferenza del tipoType inference

Quando un metodo generico viene chiamato senza specificare argomenti di tipo, un processo di inferenza del tipo tenta di dedurre gli argomenti di tipo per la chiamata.When a generic method is called without specifying type arguments, a type inference process attempts to infer type arguments for the call. La presenza dell'inferenza del tipo consente di usare una sintassi più pratica per chiamare un metodo generico e consente al programmatore di evitare di specificare informazioni sui tipi ridondanti.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. Ad esempio, data la dichiarazione del metodo: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;
    }
}

è possibile richiamare il metodo Choose senza specificare in modo esplicito un argomento di tipo: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>

Tramite l'inferenza del tipo, gli argomenti di tipo int e string sono determinati dagli argomenti al metodo.Through type inference, the type arguments int and string are determined from the arguments to the method.

L'inferenza del tipo si verifica come parte dell'elaborazione in fase di binding di una chiamata al metodo (chiamate al metodo) e viene eseguita prima del passaggio di risoluzione dell'overload della chiamata.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. Quando un particolare gruppo di metodi viene specificato in una chiamata al metodo e nessun argomento di tipo viene specificato come parte della chiamata al metodo, l'inferenza del tipo viene applicata a ogni metodo generico nel gruppo di metodi.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. Se l'inferenza del tipo ha esito positivo, gli argomenti di tipo dedotti vengono usati per determinare i tipi di argomenti per la risoluzione dell'overload successiva.If type inference succeeds, then the inferred type arguments are used to determine the types of arguments for subsequent overload resolution. Se la risoluzione dell'overload sceglie un metodo generico come quello da richiamare, gli argomenti di tipo dedotti vengono usati come argomenti di tipo effettivi per la chiamata.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. Se l'inferenza del tipo per un particolare metodo ha esito negativo, il metodo non partecipa alla risoluzione dell'overload.If type inference for a particular method fails, that method does not participate in overload resolution. L'errore di inferenza del tipo, in e di se stesso, non provoca un errore in fase di binding.The failure of type inference, in and of itself, does not cause a binding-time error. Tuttavia, spesso genera un errore in fase di binding quando la risoluzione dell'overload non riesce a trovare i metodi applicabili.However, it often leads to a binding-time error when overload resolution then fails to find any applicable methods.

Se il numero di argomenti specificato è diverso dal numero di parametri nel metodo, l'inferenza ha immediatamente esito negativo.If the supplied number of arguments is different than the number of parameters in the method, then inference immediately fails. In caso contrario, si supponga che il metodo generico abbia la firma seguente:Otherwise, assume that the generic method has the following signature:

Tr M<X1,...,Xn>(T1 x1, ..., Tm xm)

Con una chiamata al metodo nel formato M(E1...Em) l'attività di inferenza del tipo è trovare argomenti di tipo univoco S1...Sn per ognuno dei parametri di tipo X1...Xn in modo che la chiamata M<S1...Sn>(E1...Em) diventi valida.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.

Durante il processo di inferenza ogni parametro di tipo Xi è stato corretto a un determinato tipo Si o non è stato risolto con un set di limitiassociato.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. Ogni limite è un tipo T.Each of the bounds is some type T. Inizialmente ogni variabile di tipo Xi non è fissata con un set vuoto di limiti.Initially each type variable Xi is unfixed with an empty set of bounds.

L'inferenza del tipo si verifica in fasi.Type inference takes place in phases. Ogni fase tenterà di dedurre gli argomenti di tipo per più variabili di tipo in base ai risultati della fase precedente.Each phase will try to infer type arguments for more type variables based on the findings of the previous phase. La prima fase crea alcune inferenze iniziali dei limiti, mentre la seconda fase corregge le variabili di tipo in tipi specifici e deduce ulteriori limiti.The first phase makes some initial inferences of bounds, whereas the second phase fixes type variables to specific types and infers further bounds. La seconda fase può essere ripetuta per un certo numero di volte.The second phase may have to be repeated a number of times.

Nota: L'inferenza del tipo viene eseguita non solo quando viene chiamato un metodo generico.Note: Type inference takes place not only when a generic method is called. L'inferenza del tipo per la conversione dei gruppi di metodi è descritta in inferenza del tipo per la conversione dei gruppi di metodi e la ricerca del tipo comune migliore di un set di espressioni viene descritta in ricerca del tipo comune migliore di un set di espressioni.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.

Prima faseThe first phase

Per ogni argomento del metodo Ei:For each of the method arguments Ei:

  • Se Ei è una funzione anonima, viene eseguita un' inferenza esplicita del tipo di parametro (inferenza del tipo di parametro esplicito) da Ei a TiIf Ei is an anonymous function, an explicit parameter type inference (Explicit parameter type inferences) is made from Ei to Ti
  • In caso contrario, se Ei ha un tipo U e xi è un parametro di valore, viene eseguita un' inferenza con associazione inferiore da U a Ti.Otherwise, if Ei has a type U and xi is a value parameter then a lower-bound inference is made from U to Ti.
  • In caso contrario, se Ei ha un tipo U e xi è un parametro ref o out, viene eseguita un' inferenza esatta da U a Ti.Otherwise, if Ei has a type U and xi is a ref or out parameter then an exact inference is made from U to Ti.
  • In caso contrario, non viene eseguita alcuna inferenza per questo argomento.Otherwise, no inference is made for this argument.

Seconda faseThe second phase

La seconda fase procede come segue:The second phase proceeds as follows:

  • Tutte le variabili di tipo non fisse Xi che non dipendono da (dipendenza) Xj sono fisse (correzione).All unfixed type variables Xi which do not depend on (Dependence) any Xj are fixed (Fixing).
  • Se non esistono variabili di questo tipo, tutte le variabili di tipo non fisse Xi sono fisse per tutte le seguenti condizioni:If no such type variables exist, all unfixed type variables Xi are fixed for which all of the following hold:
    • Esiste almeno una variabile di tipo Xj che dipende da XiThere is at least one type variable Xj that depends on Xi
    • Xi dispone di un set di limiti non vuotoXi has a non-empty set of bounds
  • Se non esiste alcuna variabile di tipo e sono ancora presenti variabili di tipo non fisse , l'inferenza del tipo ha esito negativo.If no such type variables exist and there are still unfixed type variables, type inference fails.
  • In caso contrario, se non esistono altre variabili di tipo non fisse , l'inferenza del tipo ha esito positivo.Otherwise, if no further unfixed type variables exist, type inference succeeds.
  • In caso contrario, per tutti gli argomenti Ei con il tipo di parametro corrispondente Ti dove i tipi di output (tipi di output) contengono variabili di tipo non fisse Xj ma i tipi di input (tipi di input) non lo sono, viene eseguita un' inferenza del tipo di output (inferenza del tipo di output) da Ei a Ti.Otherwise, for all arguments Ei with corresponding parameter type Ti where the output types (Output types) contain unfixed type variables Xj but the input types (Input types) do not, an output type inference (Output type inferences) is made from Ei to Ti. Quindi, la seconda fase viene ripetuta.Then the second phase is repeated.

Tipi di inputInput types

Se E è un gruppo di metodi o una funzione anonima tipizzata in modo implicito e T è un tipo delegato o un tipo di albero delle espressioni, tutti i tipi di parametro T sono tipi di input di E con tipo 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.

Tipi di outputOutput types

Se E è un gruppo di metodi o una funzione anonima e T è un tipo delegato o un tipo di albero delle espressioni, il tipo restituito di T è un tipo di output di E con tipo 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.

DipendenzaDependence

Una variabile di tipo non fixed Xi dipende direttamente da una variabile di tipo non fixed Xj se per alcuni argomenti Ek con tipo Tk Xj si verifica in un tipo di input Ek con tipo Tk e Xi si verifica in un tipo di output Ek con tipo 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 dipende da Xi se Xj dipende direttamente dal Xi o se Xi dipende direttamente da Xk e Xk dipende da Xj.Xj depends on Xi if Xj depends directly on Xi or if Xi depends directly on Xk and Xk depends on Xj. Pertanto "dipende da" è la chiusura transitiva ma non riflessiva di "dipende direttamente da".Thus "depends on" is the transitive but not reflexive closure of "depends directly on".

Inferenza del tipo di outputOutput type inferences

Un' inferenza del tipo di output viene eseguita da un'espressione E a un tipo T nel modo seguente:An output type inference is made from an expression E to a type T in the following way:

  • Se E è una funzione anonima con tipo restituito dedotto U (tipo restituito derivato) e T è un tipo delegato o un tipo di albero delle espressioni con tipo restituito Tb, viene eseguita un' inferenza ad associazione inferiore (inferenza con associazioneinferiore) da U a Tb.If E is an anonymous function with inferred return type U (Inferred return type) and T is a delegate type or expression tree type with return type Tb, then a lower-bound inference (Lower-bound inferences) is made from U to Tb.
  • In caso contrario, se E è un gruppo di metodi e T è un tipo delegato o un tipo di albero delle espressioni con tipi di parametro T1...Tk e tipo restituito Tbe la risoluzione dell'overload di E con i tipi T1...Tk genera un solo metodo con tipo restituito U, viene eseguita un' inferenza con associazione inferiore da U a Tb.Otherwise, if E is a method group and T is a delegate type or expression tree type with parameter types T1...Tk and return type Tb, and overload resolution of E with the types T1...Tk yields a single method with return type U, then a lower-bound inference is made from U to Tb.
  • In caso contrario, se E è un'espressione con tipo U, viene eseguita un' inferenza con associazione inferiore da U a T.Otherwise, if E is an expression with type U, then a lower-bound inference is made from U to T.
  • In caso contrario, non vengono eseguite inferenze.Otherwise, no inferences are made.

Inferenza del tipo di parametro esplicitoExplicit parameter type inferences

Un' inferenza esplicita del tipo di parametro viene eseguita da un'espressione E a un tipo T nel modo seguente:An explicit parameter type inference is made from an expression E to a type T in the following way:

  • Se E è una funzione anonima tipizzata in modo esplicito con tipi di parametro U1...Uk e T è un tipo delegato o un tipo di albero delle espressioni con i tipi di parametro V1...Vk, per ogni Ui viene apportata un'inferenza esatta (Inferenze esatte) da Ui all' Vi corrispondente.If E is an explicitly typed anonymous function with parameter types U1...Uk and T is a delegate type or expression tree type with parameter types V1...Vk then for each Ui an exact inference (Exact inferences) is made from Ui to the corresponding Vi.

Inferenza esattaExact inferences

Un' inferenza esatta da un tipo U a un tipo V viene effettuata come segue:An exact inference from a type U to a type V is made as follows:

  • Se V è uno dei Xi non corretti , U viene aggiunto al set di limiti esatti per Xi.If V is one of the unfixed Xi then U is added to the set of exact bounds for Xi.

  • In caso contrario, vengono determinati i set V1...Vk e U1...Uk controllando se si verifica uno dei casi seguenti:Otherwise, sets V1...Vk and U1...Uk are determined by checking if any of the following cases apply:

    • V è un tipo di matrice V1[...] e U è un tipo di matrice U1[...] dello stesso rangoV is an array type V1[...] and U is an array type U1[...] of the same rank
    • V è il tipo V1? e U è il tipo U1?V is the type V1? and U is the type U1?
    • V è un tipo costruito C<V1...Vk>e U è un tipo costruito C<U1...Uk>V is a constructed type C<V1...Vk>and U is a constructed type C<U1...Uk>

    Se si verifica uno di questi casi, viene eseguita un' inferenza esatta da ogni Ui al Vicorrispondente.If any of these cases apply then an exact inference is made from each Ui to the corresponding Vi.

  • In caso contrario, non vengono eseguite inferenze.Otherwise no inferences are made.

Inferenza con associazione inferioreLower-bound inferences

Un' inferenza con associazione inferiore da un tipo U a un tipo V viene effettuata come segue:A lower-bound inference from a type U to a type V is made as follows:

  • Se V è uno dei Xi non corretti , U viene aggiunto al set di limiti inferiori per Xi.If V is one of the unfixed Xi then U is added to the set of lower bounds for Xi.

  • In caso contrario, se V è il tipo V1?e U è il tipo U1? viene eseguita un'inferenza del limite inferiore da U1 a V1.Otherwise, if V is the type V1?and U is the type U1? then a lower bound inference is made from U1 to V1.

  • In caso contrario, vengono determinati i set U1...Uk e V1...Vk controllando se si verifica uno dei casi seguenti:Otherwise, sets U1...Uk and V1...Vk are determined by checking if any of the following cases apply:

    • V è un tipo di matrice V1[...] e U è un tipo di matrice U1[...] (o un parametro di tipo il cui tipo di base effettivo è U1[...]) dello stesso rangoV is an array type V1[...] and U is an array type U1[...] (or a type parameter whose effective base type is U1[...]) of the same rank

    • V è uno dei IEnumerable<V1>, ICollection<V1> o IList<V1> e U è un tipo di matrice unidimensionale U1[](o un parametro di tipo il cui tipo di base effettivo è U1[])V is one of IEnumerable<V1>, ICollection<V1> or IList<V1> and U is a one-dimensional array type U1[](or a type parameter whose effective base type is U1[])

    • V è una classe costruita, una struttura, un tipo di interfaccia o delegato C<V1...Vk> ed è presente un tipo univoco C<U1...Uk> tale che U (o, se U è un parametro di tipo, la relativa classe di base effettiva o qualsiasi membro del relativo set di interfacce effettivo) è identica a, eredita da (direttamente o indirettamente) o implementa (direttamente o indirettamente) C<U1...Uk>.V is a constructed class, struct, interface or delegate type C<V1...Vk> and there is a unique type C<U1...Uk> such that U (or, if U 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>.

      La restrizione "univocità" significa che nell'interfaccia del case C<T> {} class U: C<X>, C<Y> {}, non viene eseguita alcuna inferenza quando si deduce da U a C<T> perché U1 potrebbe essere X o Y.)(The "uniqueness" restriction means that in the case interface C<T> {} class U: C<X>, C<Y> {}, then no inference is made when inferring from U to C<T> because U1 could be X or Y.)

    Se si verifica uno di questi casi, viene eseguita un'inferenza da ogni Ui al Vi corrispondente come indicato di seguito:If any of these cases apply then an inference is made from each Ui to the corresponding Vi as follows:

    • Se Ui non è noto come tipo di riferimento, viene eseguita un' inferenza esattaIf Ui is not known to be a reference type then an exact inference is made
    • In caso contrario, se U è un tipo di matrice, viene eseguita un' inferenza con associazione inferioreOtherwise, if U is an array type then a lower-bound inference is made
    • In caso contrario, se V è C<V1...Vk> l'inferenza dipende dal parametro di tipo i-th di C:Otherwise, if V is C<V1...Vk> then inference depends on the i-th type parameter of C:
      • Se è covariante, viene eseguita un' inferenza con associazione inferiore .If it is covariant then a lower-bound inference is made.
      • Se è controvariante, viene eseguita un' inferenza del limite superiore .If it is contravariant then an upper-bound inference is made.
      • Se è invariante, viene eseguita un' inferenza esatta .If it is invariant then an exact inference is made.
  • In caso contrario, non vengono eseguite inferenze.Otherwise, no inferences are made.

Inferenze con associazione superioreUpper-bound inferences

Un' inferenza con binding superiore da un tipo U a un tipo V viene effettuata come segue:An upper-bound inference from a type U to a type V is made as follows:

  • Se V è uno dei Xi non corretti , U viene aggiunto al set di limiti superiori per Xi.If V is one of the unfixed Xi then U is added to the set of upper bounds for Xi.

  • In caso contrario, vengono determinati i set V1...Vk e U1...Uk controllando se si verifica uno dei casi seguenti:Otherwise, sets V1...Vk and U1...Uk are determined by checking if any of the following cases apply:

    • U è un tipo di matrice U1[...] e V è un tipo di matrice V1[...] dello stesso rangoU is an array type U1[...] and V is an array type V1[...] of the same rank

    • U è uno dei IEnumerable<Ue>, ICollection<Ue> o IList<Ue> e V è un tipo di matrice unidimensionale Ve[]U is one of IEnumerable<Ue>, ICollection<Ue> or IList<Ue> and V is a one-dimensional array type Ve[]

    • U è il tipo U1? e V è il tipo V1?U is the type U1? and V is the type V1?

    • U è costituito da classi, struct, interfacce o tipi di delegati C<U1...Uk> e V è una classe, uno struct, un'interfaccia o un tipo di delegato identico a, eredita da (direttamente o indirettamente) o implementa (direttamente o indirettamente) un tipo univoco C<V1...Vk>U is constructed class, struct, interface or delegate type C<U1...Uk> and V is a class, struct, interface or delegate type which is identical to, inherits from (directly or indirectly), or implements (directly or indirectly) a unique type C<V1...Vk>

      La restrizione "univocità" significa che se si dispone di interface C<T>{} class V<Z>: C<X<Z>>, C<Y<Z>>{}, non viene eseguita alcuna inferenza quando si deduce da C<U1> a V<Q>.(The "uniqueness" restriction means that if we have interface C<T>{} class V<Z>: C<X<Z>>, C<Y<Z>>{}, then no inference is made when inferring from C<U1> to V<Q>. Le inferenze non vengono apportate da U1 a X<Q> o Y<Q>.)Inferences are not made from U1 to either X<Q> or Y<Q>.)

    Se si verifica uno di questi casi, viene eseguita un'inferenza da ogni Ui al Vi corrispondente come indicato di seguito:If any of these cases apply then an inference is made from each Ui to the corresponding Vi as follows:

    • Se Ui non è noto come tipo di riferimento, viene eseguita un' inferenza esattaIf Ui is not known to be a reference type then an exact inference is made
    • In caso contrario, se V è un tipo di matrice, viene eseguita un' inferenza con limite superioreOtherwise, if V is an array type then an upper-bound inference is made
    • In caso contrario, se U è C<U1...Uk> l'inferenza dipende dal parametro di tipo i-th di C:Otherwise, if U is C<U1...Uk> then inference depends on the i-th type parameter of C:
      • Se è covariante, viene eseguita un' inferenza del limite superiore .If it is covariant then an upper-bound inference is made.
      • Se è controvariante, viene eseguita un' inferenza con associazione inferiore .If it is contravariant then a lower-bound inference is made.
      • Se è invariante, viene eseguita un' inferenza esatta .If it is invariant then an exact inference is made.
  • In caso contrario, non vengono eseguite inferenze.Otherwise, no inferences are made.

FissaggioFixing

Una variabile di tipo unfixed Xi con un set di limiti viene fissata come indicato di seguito:An unfixed type variable Xi with a set of bounds is fixed as follows:

  • Il set di tipi candidati Uj inizia come set di tutti i tipi nel set di limiti per Xi.The set of candidate types Uj starts out as the set of all types in the set of bounds for Xi.
  • Si esamina quindi ogni limite per Xi a sua volta: per ogni U con binding esatto di Xi tutti i tipi Uj che non sono identici a U vengono rimossi dal set candidato.We then examine each bound for Xi in turn: For each exact bound U of Xi all types Uj which are not identical to U are removed from the candidate set. Per ogni U con binding inferiore di Xi tutti i tipi Uj a cui non è presente una conversione implicita da U vengono rimossi dal set di candidati.For each lower bound U of Xi all types Uj to which there is not an implicit conversion from U are removed from the candidate set. Per ogni U limite superiore di Xi tutti i tipi Uj da cui non esiste una conversione implicita a U vengono rimossi dal set di candidati.For each upper bound U of Xi all types Uj from which there is not an implicit conversion to U are removed from the candidate set.
  • Se tra i tipi candidati rimanenti Uj è presente un tipo univoco V da cui esiste una conversione implicita a tutti gli altri tipi candidati, Xi viene fissata V.If among the remaining candidate types Uj there is a unique type V from which there is an implicit conversion to all the other candidate types, then Xi is fixed to V.
  • In caso contrario, l'inferenza del tipo non riesce.Otherwise, type inference fails.

Tipo restituito derivatoInferred return type

Il tipo restituito derivato di una funzione anonima F viene usato durante l'inferenza del tipo e la risoluzione dell'overload.The inferred return type of an anonymous function F is used during type inference and overload resolution. Il tipo restituito derivato può essere determinato solo per una funzione anonima in cui tutti i tipi di parametro sono noti, perché sono specificati in modo esplicito, forniti tramite una conversione di funzione anonima o dedotti durante l'inferenza del tipo in un oggetto generico di inclusione chiamata al metodo.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.

Il tipo di risultato derivato viene determinato nel modo seguente:The inferred result type is determined as follows:

  • Se il corpo di F è un' espressione con un tipo, il tipo di risultato derivato di F è il tipo di tale espressione.If the body of F is an expression that has a type, then the inferred result type of F is the type of that expression.
  • Se il corpo di F è un blocco e il set di espressioni nelle istruzioni return del blocco ha un tipo di T più comune migliore (individuando il tipo comune migliore di un set di espressioni), il tipo di risultato derivato di F è T.If the body of F is a block and the set of expressions in the block's return statements has a best common type T (Finding the best common type of a set of expressions), then the inferred result type of F is T.
  • In caso contrario, non è possibile dedurre un tipo di risultato per F.Otherwise, a result type cannot be inferred for F.

Il tipo restituito derivato viene determinato nel modo seguente:The inferred return type is determined as follows:

  • Se F è async e il corpo di F è un'espressione classificata come Nothing (classificazioni di espressioni) o un blocco di istruzioni in cui nessuna istruzione return contiene espressioni, il tipo restituito derivato è System.Threading.Tasks.TaskIf F is async and the body of F is either an expression classified as nothing (Expression classifications), or a statement block where no return statements have expressions, the inferred return type is System.Threading.Tasks.Task
  • Se F è async e ha un tipo di risultato derivato T, il tipo restituito derivato è System.Threading.Tasks.Task<T>.If F is async and has an inferred result type T, the inferred return type is System.Threading.Tasks.Task<T>.
  • Se F è non asincrono e ha un tipo di risultato derivato T, il tipo restituito derivato è T.If F is non-async and has an inferred result type T, the inferred return type is T.
  • In caso contrario, non è possibile dedurre un tipo restituito per F.Otherwise a return type cannot be inferred for F.

Come esempio di inferenza del tipo che include funzioni anonime, si consideri il metodo di estensione Select dichiarato nella classe 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);
        }
    }
}

Supponendo che lo spazio dei nomi System.Linq sia stato importato con una clausola using e che una classe Customer con una proprietà Name di tipo string, è possibile usare il metodo Select per selezionare i nomi di un elenco di clienti: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);

La chiamata del metodo di estensione (chiamate al metodo di estensione) di Select viene elaborata riscrivendo la chiamata in una chiamata a un metodo statico: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);

Poiché gli argomenti di tipo non sono stati specificati in modo esplicito, viene usata l'inferenza del tipo per dedurre gli argomenti tipo.Since type arguments were not explicitly specified, type inference is used to infer the type arguments. In primo luogo, l'argomento customers è correlato al parametro source, deferendo T Customer.First, the customers argument is related to the source parameter, inferring T to be Customer. Quindi, utilizzando il processo di inferenza del tipo di funzione anonimo descritto in precedenza, a c viene assegnato il tipo Customere l'espressione c.Name è correlata al tipo restituito del parametro selector, deferendo 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. Quindi, la chiamata è equivalente aThus, the invocation is equivalent to

Sequence.Select<Customer,string>(customers, (Customer c) => c.Name)

e il risultato è di tipo IEnumerable<string>.and the result is of type IEnumerable<string>.

Nell'esempio seguente viene illustrato come l'inferenza del tipo di funzione anonima consente alle informazioni sul tipo di "propagarsi" tra gli argomenti in una chiamata a un metodo genericoThe following example demonstrates how anonymous function type inference allows type information to "flow" between arguments in a generic method invocation. Dato il metodo:Given the method:

static Z F<X,Y,Z>(X value, Func<X,Y> f1, Func<Y,Z> f2) {
    return f2(f1(value));
}

Inferenza del tipo per la chiamata:Type inference for the invocation:

double seconds = F("1:15:30", s => TimeSpan.Parse(s), t => t.TotalSeconds);

procede come segue: prima di tutto, l'argomento "1:15:30" è correlato al parametro value, deferendo X essere string.proceeds as follows: First, the argument "1:15:30" is related to the value parameter, inferring X to be string. Quindi, al parametro della prima funzione anonima, s, viene assegnato il tipo dedotto stringe l'espressione TimeSpan.Parse(s) è correlata al tipo restituito di f1, deferendo 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. Infine, al parametro della seconda funzione anonima, t, viene assegnato il tipo dedotto System.TimeSpane l'espressione t.TotalSeconds è correlata al tipo restituito di f2, deferendo 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. Il risultato della chiamata è quindi di tipo double.Thus, the result of the invocation is of type double.

Inferenza del tipo per la conversione dei gruppi di metodiType inference for conversion of method groups

Analogamente alle chiamate di metodi generici, l'inferenza del tipo deve essere applicata anche quando un gruppo di metodi M contenente un metodo generico viene convertito in un tipo delegato specificato D (conversioni di gruppidi metodi).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). Dato un metodoGiven a method

Tr M<X1...Xn>(T1 x1 ... Tm xm)

e il gruppo di metodi M essere assegnato al tipo delegato D l'attività di inferenza del tipo consiste nel trovare gli argomenti di tipo S1...Sn in modo che l'espressione: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>

diventa compatibile (dichiarazioni di Delegate) con D.becomes compatible (Delegate declarations) with D.

Diversamente dall'algoritmo di inferenza del tipo per le chiamate ai metodi generici, in questo caso sono disponibili solo tipidi argomento, nessuna espressionedi argomento.Unlike the type inference algorithm for generic method calls, in this case there are only argument types, no argument expressions. In particolare, non sono presenti funzioni anonime e pertanto non sono necessarie più fasi di inferenza.In particular, there are no anonymous functions and hence no need for multiple phases of inference.

Al contrario, tutti i Xi vengono considerati senza correzionee viene eseguita un' inferenza con associazione inferiore da ogni tipo di argomento Uj di D al tipo di parametro corrispondente Tj di 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. Se per uno dei Xi non sono stati trovati limiti, l'inferenza del tipo ha esito negativo.If for any of the Xi no bounds were found, type inference fails. In caso contrario, tutte le Xi vengono fissate alla Sicorrispondente, che sono il risultato dell'inferenza del tipo.Otherwise, all Xi are fixed to corresponding Si, which are the result of type inference.

Ricerca del tipo comune migliore di un set di espressioniFinding the best common type of a set of expressions

In alcuni casi, è necessario dedurre un tipo comune per un set di espressioni.In some cases, a common type needs to be inferred for a set of expressions. In particolare, i tipi di elemento delle matrici tipizzate in modo implicito e i tipi restituiti di funzioni anonime con corpi di blocco vengono individuati in questo modo.In particular, the element types of implicitly typed arrays and the return types of anonymous functions with block bodies are found in this way.

In modo intuitivo, dato un set di espressioni E1...Em questa inferenza dovrebbe essere equivalente alla chiamata a un metodoIntuitively, given a set of expressions E1...Em this inference should be equivalent to calling a method

Tr M<X>(X x1 ... X xm)

con il Ei come argomenti.with the Ei as arguments.

Più precisamente, l'inferenza inizia con una variabile di tipo non fissa X.More precisely, the inference starts out with an unfixed type variable X. Le inferenze del tipo di output vengono quindi eseguite da ogni Ei X.Output type inferences are then made from each Ei to X. Infine, X è fisso e, in caso di esito positivo, il tipo risultante S è il tipo comune migliore risultante per le espressioni.Finally, X is fixed and, if successful, the resulting type S is the resulting best common type for the expressions. Se tale S non esiste, le espressioni non hanno un tipo comune migliore.If no such S exists, the expressions have no best common type.

Risoluzione dell'overloadOverload resolution

La risoluzione dell'overload è un meccanismo in fase di associazione per la selezione del miglior membro di funzione da richiamare dato un elenco di argomenti e un set di membri di funzione candidati.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. Risoluzione dell'overload consente di selezionare il membro della funzione da richiamare nei contesti C#distinti seguenti all'interno di:Overload resolution selects the function member to invoke in the following distinct contexts within C#:

Ognuno di questi contesti definisce il set di membri di funzione candidati e l'elenco di argomenti in modo univoco, come descritto in dettaglio nelle sezioni elencate in precedenza.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. Ad esempio, il set di candidati per una chiamata al metodo non include i metodi contrassegnati override (ricerca di membri) e i metodi in una classe di base non sono candidati se un metodo in una classe derivata è applicabile (chiamate al metodo).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).

Una volta identificati i membri della funzione candidata e l'elenco di argomenti, la selezione del membro della funzione migliore è la stessa in tutti i casi: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:

  • Dato il set di membri di funzione candidati applicabili, viene individuato il membro della funzione migliore nel set.Given the set of applicable candidate function members, the best function member in that set is located. Se il set contiene un solo membro della funzione, il membro della funzione è il membro della funzione migliore.If the set contains only one function member, then that function member is the best function member. In caso contrario, il membro di funzione migliore è il membro di una funzione che è migliore di tutti gli altri membri della funzione rispetto all'elenco di argomenti specificato, purché ogni membro della funzione venga confrontato con tutti gli altri membri della funzione utilizzando le regole in un membro di funzione migliore.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. Se non è presente esattamente un membro di funzione migliore di tutti gli altri membri della funzione, la chiamata del membro della funzione è ambigua e si verifica un errore in fase di binding.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.

Le sezioni seguenti definiscono il significato esatto dei termini membro della funzione applicabile e membro di funzione migliore.The following sections define the exact meanings of the terms applicable function member and better function member.

Membro di funzione applicabileApplicable function member

Un membro di funzione è detto membro della funzione applicabile rispetto a un elenco di argomenti A quando si verificano tutte le condizioni seguenti: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:

  • Ogni argomento in A corrisponde a un parametro nella dichiarazione del membro della funzione, come descritto in parametri corrispondenti, e qualsiasi parametro a cui non corrisponde alcun argomento è un parametro facoltativo.Each argument in A 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.
  • Per ogni argomento in A, la modalità di passaggio del parametro dell'argomento (ad esempio, value, refo out) è identica alla modalità di passaggio del parametro del parametro corrispondente eFor each argument in A, the parameter passing mode of the argument (i.e., value, ref, or out) is identical to the parameter passing mode of the corresponding parameter, and
    • per un parametro di valore o una matrice di parametri, esiste una conversione implicita (conversioni implicite) dall'argomento al tipo del parametro corrispondente.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
    • per un parametro ref o out, il tipo dell'argomento è identico al tipo del parametro corrispondente.for a ref or out parameter, the type of the argument is identical to the type of the corresponding parameter. Dopo tutto, un ref o out parametro è un alias per l'argomento passato.After all, a ref or out parameter is an alias for the argument passed.

Per un membro di funzione che include una matrice di parametri, se il membro della funzione è applicabile dalle regole precedenti, viene definito applicabile nel formato normale.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. Se un membro di funzione che include una matrice di parametri non è applicabile nel formato normale, il membro della funzione può essere invece applicabile nel formato espanso: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:

  • Il form espanso viene costruito sostituendo la matrice di parametri nella dichiarazione del membro della funzione con zero o più parametri del valore del tipo di elemento della matrice di parametri in modo che il numero di argomenti nell'elenco di argomenti A corrisponda al numero totale di parametri.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 list A matches the total number of parameters. Se A dispone di un numero di argomenti inferiore al numero di parametri fissi nella dichiarazione del membro della funzione, il form espanso del membro della funzione non può essere costruito e pertanto non è applicabile.If A 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.
  • In caso contrario, il form espanso è applicabile se per ogni argomento in A la modalità di passaggio del parametro dell'argomento è identica alla modalità di passaggio del parametro del parametro corrispondente eOtherwise, the expanded form is applicable if for each argument in A the parameter passing mode of the argument is identical to the parameter passing mode of the corresponding parameter, and
    • per un parametro di valore fisso o un parametro di valore creato dall'espansione, esiste una conversione implicita (conversioni implicite) dal tipo dell'argomento al tipo del parametro corrispondente.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
    • per un parametro ref o out, il tipo dell'argomento è identico al tipo del parametro corrispondente.for a ref or out parameter, the type of the argument is identical to the type of the corresponding parameter.

Membro di funzione miglioreBetter function member

Ai fini della determinazione del membro di funzione migliore, un elenco di argomenti rimossi A viene costruito contenente solo le espressioni di argomento stesse nell'ordine in cui compaiono nell'elenco di argomenti originale.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.

Gli elenchi di parametri per ogni membro della funzione candidata vengono costruiti nel modo seguente:Parameter lists for each of the candidate function members are constructed in the following way:

  • Il form espanso viene usato se il membro della funzione è applicabile solo nel form espanso.The expanded form is used if the function member was applicable only in the expanded form.
  • I parametri facoltativi senza argomenti corrispondenti vengono rimossi dall'elenco di parametriOptional parameters with no corresponding arguments are removed from the parameter list
  • I parametri vengono riordinati in modo che si verifichino nella stessa posizione dell'argomento corrispondente nell'elenco di argomenti.The parameters are reordered so that they occur at the same position as the corresponding argument in the argument list.

Dato un elenco di argomenti A con un set di espressioni di argomento {E1, E2, ..., En} e due membri di funzione applicabili Mp e Mq con i tipi di parametro {P1, P2, ..., Pn} e {Q1, Q2, ..., Qn}, Mp viene definito come membro di funzione migliore rispetto a Mq seGiven 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

  • per ogni argomento, la conversione implicita da Ex a Qx non è migliore rispetto alla conversione implicita da Ex a Pxefor each argument, the implicit conversion from Ex to Qx is not better than the implicit conversion from Ex to Px, and
  • per almeno un argomento, la conversione da Ex a Px è migliore rispetto alla conversione da Ex a Qx.for at least one argument, the conversion from Ex to Px is better than the conversion from Ex to Qx.

Quando si esegue questa valutazione, se Mp o Mq è applicabile nella forma espansa, Px o Qx fa riferimento a un parametro nella forma espansa dell'elenco di parametri.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.

Se le sequenze di tipi di parametro {P1, P2, ..., Pn} e {Q1, Q2, ..., Qn} sono equivalenti (ad esempio, ogni Pi ha una conversione di identità nel Qicorrispondente), per determinare il membro della funzione migliore verranno applicate le seguenti regole di suddivisione in ordine.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.

  • Se Mp è un metodo non generico e Mq è un metodo generico, Mp è migliore di Mq.If Mp is a non-generic method and Mq is a generic method, then Mp is better than Mq.
  • In caso contrario, se Mp è applicabile nel formato normale e Mq dispone di una matrice params ed è applicabile solo nella relativa forma espansa, Mp è migliore di Mq.Otherwise, if Mp is applicable in its normal form and Mq has a params array and is applicable only in its expanded form, then Mp is better than Mq.
  • In caso contrario, se Mp ha più parametri dichiarati rispetto a Mq, Mp è migliore di Mq.Otherwise, if Mp has more declared parameters than Mq, then Mp is better than Mq. Questo problema può verificarsi se entrambi i metodi hanno params matrici e sono applicabili solo nei moduli espansi.This can occur if both methods have params arrays and are applicable only in their expanded forms.
  • In caso contrario, se tutti i parametri di Mp hanno un argomento corrispondente mentre gli argomenti predefiniti devono essere sostituiti da almeno un parametro facoltativo in Mq, Mp è migliore di Mq.Otherwise if all parameters of Mp have a corresponding argument whereas default arguments need to be substituted for at least one optional parameter in Mq then Mp is better than Mq.
  • In caso contrario, se Mp dispone di tipi di parametro più specifici rispetto a Mq, Mp è migliore di Mq.Otherwise, if Mp has more specific parameter types than Mq, then Mp is better than Mq. Let {R1, R2, ..., Rn} e {S1, S2, ..., Sn} rappresentano i tipi di parametro senza istanze e non espansi di Mp e Mq.Let {R1, R2, ..., Rn} and {S1, S2, ..., Sn} represent the uninstantiated and unexpanded parameter types of Mp and Mq. i tipi di parametro di Mpsono più specifici del Mqse, per ogni parametro Rx non è meno specifico di Sxe, per almeno un parametro, Rx è più specifico di Sx:Mp's parameter types are more specific than Mq's if, for each parameter, Rx is not less specific than Sx, and, for at least one parameter, Rx is more specific than Sx:
    • Un parametro di tipo è meno specifico di un parametro non di tipo.A type parameter is less specific than a non-type parameter.
    • In modo ricorsivo, un tipo costruito è più specifico di un altro tipo costruito (con lo stesso numero di argomenti di tipo) se almeno un argomento di tipo è più specifico e nessun argomento di tipo è meno specifico dell'argomento di tipo corrispondente nell'altro.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.
    • Un tipo di matrice è più specifico di un altro tipo di matrice (con lo stesso numero di dimensioni) se il tipo di elemento del primo è più specifico del tipo di elemento del secondo.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.
  • In caso contrario, se un membro è un operatore non Lift e l'altro è un operatore lifted, è preferibile che non si sollevi.Otherwise if one member is a non-lifted operator and the other is a lifted operator, the non-lifted one is better.
  • In caso contrario, nessun membro della funzione è migliore.Otherwise, neither function member is better.

Migliore conversione dall'espressioneBetter conversion from expression

Dato un C1 di conversione implicita che converte da un'espressione E a un tipo T1e un C2 di conversione implicita che converte da un'espressione E a un tipo T2, C1 è una conversione migliore rispetto a C2 se E non corrisponde esattamente T2 e almeno una delle seguenti contiene: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:

Espressione corrispondente esattaExactly matching Expression

Data un'espressione E e un tipo T, E corrisponde esattamente T se uno dei seguenti include:Given an expression E and a type T, E exactly matches T if one of the following holds:

  • E dispone di un tipo Sed esiste una conversione di identità da S a TE has a type S, and an identity conversion exists from S to T
  • E è una funzione anonima, T è un tipo di delegato D o un tipo di albero delle espressioni Expression<D> e uno degli elementi seguenti include:E is an anonymous function, T is either a delegate type D or an expression tree type Expression<D> and one of the following holds:
    • Un tipo restituito derivato X esiste per E nel contesto dell'elenco di parametri di D (tipo restituito derivato) ed esiste una conversione di identità da X al tipo restituito di DAn inferred return type X exists for E in the context of the parameter list of D (Inferred return type), and an identity conversion exists from X to the return type of D
    • E è non asincrono e D ha un tipo restituito Y o E è async e D ha un tipo restituito Task<Y>e uno dei valori seguenti contiene:Either E is non-async and D has a return type Y or E is async and D has a return type Task<Y>, and one of the following holds:
      • Il corpo di E è un'espressione che corrisponde esattamente YThe body of E is an expression that exactly matches Y
      • Il corpo di E è un blocco di istruzioni in cui ogni istruzione return restituisce un'espressione che corrisponde esattamente YThe body of E is a statement block where every return statement returns an expression that exactly matches Y

Migliore destinazione di conversioneBetter conversion target

Dati due tipi diversi T1 e T2, T1 è una destinazione di conversione migliore rispetto a T2 se non esiste alcuna conversione implicita da T2 a T1 ed è presente almeno uno dei seguenti elementi: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:

  • Esiste una conversione implicita da T1 a T2An implicit conversion from T1 to T2 exists
  • T1 è un tipo delegato D1 o un tipo di albero delle espressioni Expression<D1>, T2 è un tipo delegato D2 o un tipo di albero delle espressioni Expression<D2>, D1 ha un tipo restituito S1 e uno dei seguenti contiene:T1 is either a delegate type D1 or an expression tree type Expression<D1>, T2 is either a delegate type D2 or an expression tree type Expression<D2>, D1 has a return type S1 and one of the following holds:
    • D2 restituisce voidD2 is void returning
    • D2 dispone di un tipo restituito S2e S1 è una destinazione di conversione migliore rispetto a S2D2 has a return type S2, and S1 is a better conversion target than S2
  • T1 è Task<S1>, T2 è Task<S2>e S1 è una destinazione di conversione migliore rispetto a S2T1 is Task<S1>, T2 is Task<S2>, and S1 is a better conversion target than S2
  • T1 è S1 o S1? dove S1 è un tipo integrale con segno e T2 è S2 o S2? dove S2 è un tipo integrale senza segno.T1 is S1 or S1? where S1 is a signed integral type, and T2 is S2 or S2? where S2 is an unsigned integral type. In particolare:Specifically:
    • S1 è sbyte e S2 è byte, ushort, uinto ulongS1 is sbyte and S2 is byte, ushort, uint, or ulong
    • S1 è short e S2 è ushort, uinto ulongS1 is short and S2 is ushort, uint, or ulong
    • S1 è int e S2 è uinto ulongS1 is int and S2 is uint, or ulong
    • S1 è long e S2 è ulongS1 is long and S2 is ulong

Overload in classi genericheOverloading in generic classes

Mentre le firme dichiarate devono essere univoche, è possibile che la sostituzione di argomenti di tipo comportasse firme identiche.While signatures as declared must be unique, it is possible that substitution of type arguments results in identical signatures. In questi casi, le regole di associazione della risoluzione dell'overload precedente preleveranno il membro più specifico.In such cases, the tie-breaking rules of overload resolution above will pick the most specific member.

Gli esempi seguenti mostrano gli overload validi e non validi in base a questa regola: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);
}

Verifica della risoluzione dell'overload dinamico in fase di compilazioneCompile-time checking of dynamic overload resolution

Per la maggior parte delle operazioni con associazione dinamica il set di possibili candidati per la risoluzione non è noto in fase di compilazione.For most dynamically bound operations the set of possible candidates for resolution is unknown at compile-time. In alcuni casi, tuttavia, il set di candidati è noto in fase di compilazione:In certain cases, however the candidate set is known at compile-time:

  • Chiamate di metodo statiche con argomenti dinamiciStatic method calls with dynamic arguments
  • Chiamate al metodo di istanza in cui il ricevitore non è un'espressione dinamicaInstance method calls where the receiver is not a dynamic expression
  • L'indicizzatore chiama dove il ricevitore non è un'espressione dinamicaIndexer calls where the receiver is not a dynamic expression
  • Chiamate al costruttore con argomenti dinamiciConstructor calls with dynamic arguments

In questi casi viene eseguito un controllo in fase di compilazione limitato per ogni candidato per verificare se una di esse potrebbe essere applicata in fase di esecuzione. Questo controllo è costituito dai passaggi seguenti: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:

  • Inferenza del tipo parziale: qualsiasi argomento di tipo che non dipende direttamente o indirettamente da un argomento di tipo dynamic viene dedotto usando le regole dell' inferenza del tipo.Partial type inference: Any type argument that does not depend directly or indirectly on an argument of type dynamic is inferred using the rules of Type inference. Gli argomenti di tipo rimanenti sono sconosciuti.The remaining type arguments are unknown.
  • Verifica dell'applicabilità parziale: l'applicabilità viene controllata in base al membro della funzione applicabile, ignorando però i parametri i cui tipi sono sconosciuti.Partial applicability check: Applicability is checked according to Applicable function member, but ignoring parameters whose types are unknown.
  • Se nessun candidato supera questo test, si verificherà un errore in fase di compilazione.If no candidate passes this test, a compile-time error occurs.

Chiamata del membro di funzioneFunction member invocation

In questa sezione viene descritto il processo che si verifica in fase di esecuzione per richiamare un particolare membro di funzione.This section describes the process that takes place at run-time to invoke a particular function member. Si presuppone che un processo in fase di binding abbia già determinato il membro specifico da richiamare, eventualmente applicando la risoluzione dell'overload a un set di membri della funzione candidata.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.

Ai fini della descrizione del processo di chiamata, i membri della funzione sono divisi in due categorie:For purposes of describing the invocation process, function members are divided into two categories:

  • Membri della funzione statica.Static function members. Si tratta di costruttori di istanza, metodi statici, funzioni di accesso alle proprietà statiche e operatori definiti dall'utente.These are instance constructors, static methods, static property accessors, and user-defined operators. I membri della funzione statica sono sempre non virtuali.Static function members are always non-virtual.
  • Membri della funzione di istanza.Instance function members. Si tratta di metodi di istanza, funzioni di accesso alle proprietà dell'istanza e funzioni di accesso dell'indicizzatore.These are instance methods, instance property accessors, and indexer accessors. I membri della funzione di istanza non sono virtuali o virtuali e vengono sempre richiamati in una particolare istanza.Instance function members are either non-virtual or virtual, and are always invoked on a particular instance. L'istanza viene calcolata da un'espressione di istanza e diventa accessibile all'interno del membro della funzione come this (questo accesso).The instance is computed by an instance expression, and it becomes accessible within the function member as this (This access).

L'elaborazione in fase di esecuzione della chiamata di un membro di funzione è costituita dai passaggi seguenti, in cui M è il membro della funzione e, se M è un membro di istanza, E è l'espressione dell'istanza: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:

  • Se M è un membro della funzione statica:If M is a static function member:

    • L'elenco di argomenti viene valutato come descritto negli elenchi di argomenti.The argument list is evaluated as described in Argument lists.
    • Viene richiamato M.M is invoked.
  • Se M è un membro della funzione di istanza dichiarato in una value_type:If M is an instance function member declared in a value_type:

    • E viene valutata.E is evaluated. Se questa valutazione causa un'eccezione, non vengono eseguiti altri passaggi.If this evaluation causes an exception, then no further steps are executed.
    • Se E non è classificato come variabile, viene creata una variabile locale temporanea del tipo di Ee il valore di E viene assegnato a tale variabile.If E is not classified as a variable, then a temporary local variable of E's type is created and the value of E is assigned to that variable. E viene quindi riclassificato come riferimento a tale variabile locale temporanea.E is then reclassified as a reference to that temporary local variable. La variabile temporanea è accessibile come this all'interno di M, ma non in altro modo.The temporary variable is accessible as this within M, but not in any other way. Pertanto, solo quando E è una vera variabile, il chiamante può osservare le modifiche apportate da M a this.Thus, only when E is a true variable is it possible for the caller to observe the changes that M makes to this.
    • L'elenco di argomenti viene valutato come descritto negli elenchi di argomenti.The argument list is evaluated as described in Argument lists.
    • Viene richiamato M.M is invoked. La variabile a cui fa riferimento E diventa la variabile a cui viene fatto riferimento da this.The variable referenced by E becomes the variable referenced by this.
  • Se M è un membro della funzione di istanza dichiarato in una reference_type:If M is an instance function member declared in a reference_type:

    • E viene valutata.E is evaluated. Se questa valutazione causa un'eccezione, non vengono eseguiti altri passaggi.If this evaluation causes an exception, then no further steps are executed.
    • L'elenco di argomenti viene valutato come descritto negli elenchi di argomenti.The argument list is evaluated as described in Argument lists.
    • Se il tipo di E è un value_type, viene eseguita una conversione boxing (conversioni boxing) per convertire E nel tipo objecte E viene considerato di tipo object nei passaggi seguenti.If the type of E is a value_type, a boxing conversion (Boxing conversions) is performed to convert E to type object, and E is considered to be of type object in the following steps. In questo caso, M può essere solo un membro di System.Object.In this case, M could only be a member of System.Object.
    • Il valore di E viene verificato come valido.The value of E is checked to be valid. Se il valore di E è null, viene generata un'System.NullReferenceException e non vengono eseguiti altri passaggi.If the value of E is null, a System.NullReferenceException is thrown and no further steps are executed.
    • Viene determinata l'implementazione del membro della funzione da richiamare:The function member implementation to invoke is determined:
      • Se il tipo in fase di binding di E è un'interfaccia, il membro della funzione da richiamare è l'implementazione di M fornita dal tipo di runtime dell'istanza a cui fa riferimento E.If the binding-time type of E is an interface, the function member to invoke is the implementation of M provided by the run-time type of the instance referenced by E. Questo membro di funzione viene determinato applicando le regole di mapping dell'interfaccia (mapping dell'interfaccia) per determinare l'implementazione di M fornita dal tipo di runtime dell'istanza a cui fa riferimento E.This function member is determined by applying the interface mapping rules (Interface mapping) to determine the implementation of M provided by the run-time type of the instance referenced by E.
      • In caso contrario, se M è un membro di funzione virtuale, il membro della funzione da richiamare è l'implementazione di M fornita dal tipo di runtime dell'istanza a cui fa riferimento E.Otherwise, if M is a virtual function member, the function member to invoke is the implementation of M provided by the run-time type of the instance referenced by E. Questo membro di funzione viene determinato applicando le regole per determinare l'implementazione (metodi virtuali) più derivata di M rispetto al tipo di runtime dell'istanza a cui fa riferimento E.This function member is determined by applying the rules for determining the most derived implementation (Virtual methods) of M with respect to the run-time type of the instance referenced by E.
      • In caso contrario, M è un membro di funzione non virtuale e il membro della funzione da richiamare è M stesso.Otherwise, M is a non-virtual function member, and the function member to invoke is M itself.
    • Viene richiamata l'implementazione del membro di funzione determinata nel passaggio precedente.The function member implementation determined in the step above is invoked. L'oggetto a cui fa riferimento E diventa l'oggetto a cui fa riferimento this.The object referenced by E becomes the object referenced by this.

Chiamate nelle istanze boxedInvocations on boxed instances

Un membro di funzione implementato in un value_type può essere richiamato tramite un'istanza boxed di che value_type nelle situazioni seguenti:A function member implemented in a value_type can be invoked through a boxed instance of that value_type in the following situations:

  • Quando il membro della funzione è un override di un metodo ereditato dal tipo object e viene richiamato tramite un'espressione di istanza di tipo object.When the function member is an override of a method inherited from type object and is invoked through an instance expression of type object.
  • Quando il membro della funzione è un'implementazione di un membro di funzione di interfaccia e viene richiamato tramite un'espressione di istanza di un 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.
  • Quando il membro della funzione viene richiamato tramite un delegato.When the function member is invoked through a delegate.

In queste situazioni, l'istanza boxed viene considerata come contenente una variabile del value_typee questa variabile diventa la variabile a cui fa riferimento this all'interno della chiamata del membro della funzione.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 particolare, ciò significa che quando un membro di funzione viene richiamato su un'istanza boxed, il membro della funzione può modificare il valore contenuto nell'istanza boxed.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.

Espressioni principali:Primary expressions

Le espressioni primarie includono forme di espressioni più semplici.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
    ;

Le espressioni primarie sono divise tra array_creation_expressions e primary_no_array_creation_expressions.Primary expressions are divided between array_creation_expressions and primary_no_array_creation_expressions. Il trattamento di array-creation-expression in questo modo, anziché elencarlo insieme ad altre semplici forme di espressioni, consente alla grammatica di impedire codice potenzialmente confuso, ad esempioTreating 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];

che altrimenti verrebbe interpretato comewhich would otherwise be interpreted as

object o = (new int[3])[1];

Valori letteraliLiterals

Un primary_expression costituito da un valore letterale (valori letterali) viene classificato come valore.A primary_expression that consists of a literal (Literals) is classified as a value.

Stringhe interpolateInterpolated strings

Un interpolated_string_expression è costituito da un segno di $ seguito da un valore letterale stringa normale o Verbatim, dove buchi, delimitati da { e }, racchiudere le espressioni e le specifiche di formattazione.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. Un'espressione stringa interpolata è il risultato di un interpolated_string_literal suddiviso in singoli token, come descritto in valori letterali stringa interpolata.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)+
    ;

Il constant_expression in un'interpolazione deve disporre di una conversione implicita in int.The constant_expression in an interpolation must have an implicit conversion to int.

Un interpolated_string_expression è classificato come valore.An interpolated_string_expression is classified as a value. Se viene immediatamente convertita in System.IFormattable o System.FormattableString con una conversione di stringa interpolata implicita (conversioni implicite di stringheinterpolate), il tipo dell'espressione stringa interpolata è.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. In caso contrario, ha il tipo string.Otherwise, it has the type string.

Se il tipo di una stringa interpolata è System.IFormattable o System.FormattableString, il significato è una chiamata a 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. Se il tipo è string, il significato dell'espressione è una chiamata a string.Format.If the type is string, the meaning of the expression is a call to string.Format. In entrambi i casi, l'elenco di argomenti della chiamata è costituito da un valore letterale stringa di formato con segnaposto per ogni interpolazione e da un argomento per ogni espressione corrispondente ai segnaposto.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.

Il valore letterale stringa di formato viene costruito come indicato di seguito, dove N è il numero di interpolazioni nel interpolated_string_expression:The format string literal is constructed as follows, where N is the number of interpolations in the interpolated_string_expression:

  • Se un interpolated_regular_string_whole o un interpolated_verbatim_string_whole segue il segno di $, il valore letterale della stringa di formato è tale token.If an interpolated_regular_string_whole or an interpolated_verbatim_string_whole follows the $ sign, then the format string literal is that token.
  • In caso contrario, il valore letterale stringa di formato è costituito da:Otherwise, the format string literal consists of:
    • Primo interpolated_regular_string_start o interpolated_verbatim_string_startFirst the interpolated_regular_string_start or interpolated_verbatim_string_start
    • Quindi, per ogni numero I da 0 a N-1:Then for each number I from 0 to N-1:
      • Rappresentazione decimale di IThe decimal representation of I
      • Quindi, se l' interpolazione corrispondente dispone di un constant_expression, un , (virgola) seguito dalla rappresentazione decimale del valore del constant_expressionThen, if the corresponding interpolation has a constant_expression, a , (comma) followed by the decimal representation of the value of the constant_expression
      • Quindi il interpolated_regular_string_mid, interpolated_regular_string_end, interpolated_verbatim_string_mid o interpolated_verbatim_string_end immediatamente dopo l'interpolazione corrispondente.Then the interpolated_regular_string_mid, interpolated_regular_string_end, interpolated_verbatim_string_mid or interpolated_verbatim_string_end immediately following the corresponding interpolation.

Gli argomenti successivi sono semplicemente le espressioni delle interpolazioni (se presenti), nell'ordine.The subsequent arguments are simply the expressions from the interpolations (if any), in order.

TODO: esempi.TODO: examples.

Nomi sempliciSimple names

Un simple_name è costituito da un identificatore, seguito facoltativamente da un elenco di argomenti di tipo:A simple_name consists of an identifier, optionally followed by a type argument list:

simple_name
    : identifier type_argument_list?
    ;

Un simple_name è del form I o del form I<A1,...,Ak>, dove I è un identificatore singolo e <A1,...,Ak> è un type_argument_listfacoltativo.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. Quando non viene specificato alcun type_argument_list , provare K a essere zero.When no type_argument_list is specified, consider K to be zero. Il simple_name viene valutato e classificato come segue:The simple_name is evaluated and classified as follows:

  • Se K è zero e il simple_name viene visualizzato all'interno di un blocco e se lo spazio di dichiarazione della variabile locale del blocco(o un bloccodi inclusione) contieneuna variabile locale, un parametro o una costante con nome I, il simple_name fa riferimento a tale variabile, parametro o costante locale ed è classificato come variabile o valore.If K 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 name I, then the simple_name refers to that local variable, parameter or constant and is classified as a variable or value.

  • Se K è zero e il simple_name viene visualizzato all'interno del corpo di una dichiarazione di metodo generico e se tale dichiarazione include un parametro di tipo con nome I, il simple_name fa riferimento a tale parametro di tipo.If K is zero and the simple_name appears within the body of a generic method declaration and if that declaration includes a type parameter with name I, then the simple_name refers to that type parameter.

  • In caso contrario, per ogni tipo di istanza T (il tipo di istanza), a partire dal tipo di istanza della dichiarazione di tipo che lo contiene immediatamente e continuando con il tipo di istanza di ogni classe contenitore o dichiarazione struct (se presente):Otherwise, for each instance type T (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):

    • Se K è zero e la dichiarazione di T include un parametro di tipo con nome I, il simple_name fa riferimento a tale parametro di tipo.If K is zero and the declaration of T includes a type parameter with name I, then the simple_name refers to that type parameter.
    • In caso contrario, se la ricerca di un membro (ricerca di membri) di I T con argomenti di tipo K genera una corrispondenza:Otherwise, if a member lookup (Member lookup) of I in T with K type arguments produces a match:
      • Se T è il tipo di istanza della classe o del tipo struct che lo contiene immediatamente e la ricerca identifica uno o più metodi, il risultato è un gruppo di metodi a cui è associata un'espressione di istanza di this.If T 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 of this. Se è stato specificato un elenco di argomenti di tipo, questo viene usato nella chiamata a un metodo generico (chiamate alMetodo).If a type argument list was specified, it is used in calling a generic method (Method invocations).
      • In caso contrario, se T è il tipo di istanza della classe o del tipo struct che lo contiene immediatamente, se la ricerca identifica un membro di istanza e se il riferimento si verifica all'interno del corpo di un costruttore di istanza, un metodo di istanza o una funzione di accesso dell'istanza, il risultato è lo stesso di un accesso ai membri (accesso ai membri) del form this.I.Otherwise, if T 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 form this.I. Questo problema può verificarsi solo quando K è zero.This can only happen when K is zero.
      • In caso contrario, il risultato è lo stesso di un accesso ai membri (accesso ai membri) nel formato T.I o T.I<A1,...,Ak>.Otherwise, the result is the same as a member access (Member access) of the form T.I or T.I<A1,...,Ak>. In questo caso, si tratta di un errore in fase di binding affinché il simple_name faccia riferimento a un membro di istanza.In this case, it is a binding-time error for the simple_name to refer to an instance member.
  • In caso contrario, per ogni spazio dei nomi N, a partire dallo spazio dei nomi in cui si verifica il simple_name , continuando con ogni spazio dei nomi che lo contiene, se presente, e terminando con lo spazio dei nomi globale, i passaggi seguenti vengono valutati fino a quando non si individua un'entitàOtherwise, for each namespace N, 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:

    • Se K è zero e I è il nome di uno spazio dei nomi in N, quindi:If K is zero and I is the name of a namespace in N, then:
      • Se il percorso in cui si verifica la simple_name è racchiuso da una dichiarazione dello spazio dei nomi per N e la dichiarazione dello spazio dei nomi contiene un extern_alias_directive o using_alias_directive che associa il nome I a uno spazio dei nomi o a un tipo, il simple_name è ambiguo e si verifica un errore in fase di compilazione.If the location where the simple_name occurs is enclosed by a namespace declaration for N and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the name I with a namespace or type, then the simple_name is ambiguous and a compile-time error occurs.
      • In caso contrario, il simple_name si riferisce allo spazio dei nomi denominato I in N.Otherwise, the simple_name refers to the namespace named I in N.
    • In caso contrario, se N contiene un tipo accessibile con nome I e Kparametri di tipo  :Otherwise, if N contains an accessible type having name I and K type parameters, then:
      • Se K è zero e il percorso in cui si verifica l' simple_name è racchiuso da una dichiarazione dello spazio dei nomi per N e la dichiarazione dello spazio dei nomi contiene un extern_alias_directive o using_alias_directive che associa il nome I con uno spazio dei nomi o un tipo, il simple_name è ambiguo e si verifica un errore in fase di compilazione.If K is zero and the location where the simple_name occurs is enclosed by a namespace declaration for N and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the name I with a namespace or type, then the simple_name is ambiguous and a compile-time error occurs.
      • In caso contrario, il namespace_or_type_name si riferisce al tipo costruito con gli argomenti di tipo specificati.Otherwise, the namespace_or_type_name refers to the type constructed with the given type arguments.
    • In caso contrario, se il percorso in cui si verifica il simple_name è racchiuso da una dichiarazione dello spazio dei nomi per N:Otherwise, if the location where the simple_name occurs is enclosed by a namespace declaration for N:
      • Se K è zero e la dichiarazione dello spazio dei nomi contiene un extern_alias_directive o using_alias_directive che associa il nome I con uno spazio dei nomi o un tipo importato, il simple_name fa riferimento a tale spazio dei nomi o tipo.If K is zero and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the name I with an imported namespace or type, then the simple_name refers to that namespace or type.
      • In caso contrario, se gli spazi dei nomi e le dichiarazioni di tipo importati dal using_namespace_directives e using_static_directives della dichiarazione dello spazio dei nomi contengono esattamente un tipo accessibile o un membro statico non di estensione con nome I e Kparametri di tipo  , il simple_name si riferisce a quel tipo o membro costruito con gli argomenti di tipo specificati.Otherwise, if the namespaces and type declarations imported by the using_namespace_directives and using_static_directives of the namespace declaration contain exactly one accessible type or non-extension static member having name I and K type parameters, then the simple_name refers to that type or member constructed with the given type arguments.
      • In caso contrario, se gli spazi dei nomi e i tipi importati dal using_namespace_directivedella dichiarazione dello spazio dei nomi contengono più di un tipo accessibile o un membro statico del metodo non di estensione con nome I e K parametri di tipo, il simple_name è ambiguo e si verifica un errore.Otherwise, if the namespaces and types imported by the using_namespace_directives of the namespace declaration contain more than one accessible type or non-extension-method static member having name I and K type parameters, then the simple_name is ambiguous and an error occurs.

    Si noti che questo passaggio intero è esattamente parallelo al passaggio corrispondente nell'elaborazione di un namespace_or_type_name (nomi di spazio dei nomi e di tipo).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).

  • In caso contrario, il simple_name non è definito e si verifica un errore in fase di compilazione.Otherwise, the simple_name is undefined and a compile-time error occurs.

Espressioni racchiuse tra parentesiParenthesized expressions

Un parenthesized_expression è costituito da un' espressione racchiusa tra parentesi.A parenthesized_expression consists of an expression enclosed in parentheses.

parenthesized_expression
    : '(' expression ')'
    ;

Una parenthesized_expression viene valutata valutando l' espressione all'interno delle parentesi.A parenthesized_expression is evaluated by evaluating the expression within the parentheses. Se l' espressione racchiusa tra parentesi denota uno spazio dei nomi o un tipo, si verificherà un errore in fase di compilazione.If the expression within the parentheses denotes a namespace or type, a compile-time error occurs. In caso contrario, il risultato della parenthesized_expression è il risultato della valutazione dell' espressionecontenuta.Otherwise, the result of the parenthesized_expression is the result of the evaluation of the contained expression.

Accesso ai membriMember access

Un member_access è costituito da un primary_expression, un predefined_typeo un qualified_alias_memberseguito da un token ".", seguito da un identificatore, seguito facoltativamente da un 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'
    ;

Il qualified_alias_member produzione viene definito nei qualificatori degli alias degli spazi dei nomi.The qualified_alias_member production is defined in Namespace alias qualifiers.

Un member_access è nel formato E.I o nel formato E.I<A1, ..., Ak>, dove E è un'espressione primaria, I è un identificatore singolo e <A1, ..., Ak> è un type_argument_listfacoltativo.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. Quando non viene specificato alcun type_argument_list , provare K a essere zero.When no type_argument_list is specified, consider K to be zero.

Un member_access con una primary_expression di tipo dynamic è associato in modo dinamico (associazione dinamica).A member_access with a primary_expression of type dynamic is dynamically bound (Dynamic binding). In questo caso, il compilatore classifica l'accesso ai membri come accesso alla proprietà di tipo dynamic.In this case the compiler classifies the member access as a property access of type dynamic. Le regole seguenti per determinare il significato della member_access vengono quindi applicate in fase di esecuzione, usando il tipo di runtime anziché il tipo in fase di compilazione del primary_expression.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. Se questa classificazione in fase di esecuzione conduce a un gruppo di metodi, l'accesso ai membri deve essere il primary_expression di un invocation_expression.If this run-time classification leads to a method group, then the member access must be the primary_expression of an invocation_expression.

Il member_access viene valutato e classificato come segue:The member_access is evaluated and classified as follows:

  • Se K è zero e E è uno spazio dei nomi e E contiene uno spazio dei nomi annidato con nome I, il risultato è tale spazio dei nomi.If K is zero and E is a namespace and E contains a nested namespace with name I, then the result is that namespace.
  • In caso contrario, se E è uno spazio dei nomi e E contiene un tipo accessibile con nome I e Kparametri di tipo  , il risultato sarà il tipo costruito con gli argomenti di tipo specificati.Otherwise, if E is a namespace and E contains an accessible type having name I and K type parameters, then the result is that type constructed with the given type arguments.
  • Se E è un predefined_type o un primary_expression Classificato come tipo, se E non è un parametro di tipo e se una ricerca di membri (ricerca di membri) di I in E con Kparametri di tipo  genera una corrispondenza, E.I viene valutata e classificata come segue:If E is a predefined_type or a primary_expression classified as a type, if E is not a type parameter, and if a member lookup (Member lookup) of I in E with K type parameters produces a match, then E.I is evaluated and classified as follows:
    • Se I identifica un tipo, il risultato è il tipo costruito con gli argomenti di tipo specificati.If I identifies a type, then the result is that type constructed with the given type arguments.
    • Se I identifica uno o più metodi, il risultato è un gruppo di metodi a cui non è associata alcuna espressione di istanza.If I identifies one or more methods, then the result is a method group with no associated instance expression. Se è stato specificato un elenco di argomenti di tipo, questo viene usato nella chiamata a un metodo generico (chiamate alMetodo).If a type argument list was specified, it is used in calling a generic method (Method invocations).
    • Se I identifica una proprietà di static, il risultato è l'accesso a una proprietà senza espressione dell'istanza associata.If I identifies a static property, then the result is a property access with no associated instance expression.
    • Se I identifica un campo di static:If I identifies a static field:
      • Se il campo è readonly e il riferimento si verifica all'esterno del costruttore statico della classe o dello struct in cui viene dichiarato il campo, il risultato è un valore, ovvero il valore del campo statico I in E.If the field is readonly 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 field I in E.
      • In caso contrario, il risultato è una variabile, vale a dire il campo statico I in E.Otherwise, the result is a variable, namely the static field I in E.
    • Se I identifica un evento di static:If I identifies a static event:
      • Se il riferimento si verifica all'interno della classe o dello struct in cui viene dichiarato l'evento e l'evento è stato dichiarato senza event_accessor_declarations (eventi), E.I viene elaborato esattamente come se I fosse un campo statico.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), then E.I is processed exactly as if I were a static field.
      • In caso contrario, il risultato è un accesso a eventi senza espressione di istanza associata.Otherwise, the result is an event access with no associated instance expression.
    • Se I identifica una costante, il risultato è un valore, ovvero il valore della costante.If I identifies a constant, then the result is a value, namely the value of that constant.
    • Se I identifica un membro di enumerazione, il risultato è un valore, ovvero il valore del membro di enumerazione.If I identifies an enumeration member, then the result is a value, namely the value of that enumeration member.
    • In caso contrario, E.I è un riferimento al membro non valido e si verifica un errore in fase di compilazione.Otherwise, E.I is an invalid member reference, and a compile-time error occurs.
  • Se E è un accesso a proprietà, l'accesso a un indicizzatore, una variabile o un valore, il tipo di Te una ricerca di membri (ricerca di membri) di I in T con Kargomenti di tipo  genera una corrispondenza, E.I viene valutata e classificata come segue:If E is a property access, indexer access, variable, or value, the type of which is T, and a member lookup (Member lookup) of I in T with K type arguments produces a match, then E.I is evaluated and classified as follows:
    • Prima di tutto, se E è un accesso a una proprietà o a un indicizzatore, viene ottenuto il valore dell'accesso alla proprietà o all'indicizzatore (valori di espressioni) e E viene riclassificato come valore.First, if E is a property or indexer access, then the value of the property or indexer access is obtained (Values of expressions) and E is reclassified as a value.
    • Se I identifica uno o più metodi, il risultato è un gruppo di metodi a cui è associata un'espressione di istanza di E.If I identifies one or more methods, then the result is a method group with an associated instance expression of E. Se è stato specificato un elenco di argomenti di tipo, questo viene usato nella chiamata a un metodo generico (chiamate alMetodo).If a type argument list was specified, it is used in calling a generic method (Method invocations).
    • Se I identifica una proprietà dell'istanza,If I identifies an instance property,
      • Se E è this, I identifica una proprietà implementata automaticamente (proprietà implementate automaticamente) senza setter e il riferimento si verifica all'interno di un costruttore di istanza per un tipo di classe o struct T, quindi il risultato è una variabile, ovvero il campo sottostante nascosto per la proprietà automatica fornita da I nell'istanza di T fornita da this.If E is this, 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 type T, then the result is a variable, namely the hidden backing field for the auto-property given by I in the instance of T given by this.
      • In caso contrario, il risultato è l'accesso a una proprietà con un'espressione di istanza associata di E.Otherwise, the result is a property access with an associated instance expression of E.
    • Se T è un class_type e I identifica un campo di istanza di tale class_type:If T is a class_type and I identifies an instance field of that class_type:
      • Se il valore di E è null, viene generata un'System.NullReferenceException.If the value of E is null, then a System.NullReferenceException is thrown.
      • In caso contrario, se il campo è readonly e il riferimento si verifica all'esterno di un costruttore di istanza della classe in cui viene dichiarato il campo, il risultato è un valore, ovvero il valore del campo I nell'oggetto a cui fa riferimento E.Otherwise, if the field is readonly 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 field I in the object referenced by E.
      • In caso contrario, il risultato è una variabile, vale a dire il campo I nell'oggetto a cui fa riferimento E.Otherwise, the result is a variable, namely the field I in the object referenced by E.
    • Se T è un struct_type e I identifica un campo di istanza di tale struct_type:If T is a struct_type and I identifies an instance field of that struct_type:
      • Se E è un valore o se il campo è readonly e il riferimento si verifica all'esterno di un costruttore di istanza dello struct in cui viene dichiarato il campo, il risultato è un valore, ovvero il valore del campo I nell'istanza struct fornita da E.If E is a value, or if the field is readonly 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 field I in the struct instance given by E.
      • In caso contrario, il risultato è una variabile, vale a dire il campo I nell'istanza struct fornita da E.Otherwise, the result is a variable, namely the field I in the struct instance given by E.
    • Se I identifica un evento di istanza:If I identifies an instance event:
      • Se il riferimento si verifica all'interno della classe o dello struct in cui viene dichiarato l'evento e l'evento è stato dichiarato senza event_accessor_declarations (eventi) e il riferimento non viene eseguito come lato sinistro di un operatore += o -=, E.I viene elaborato esattamente come se I fosse un campo di istanza.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, then E.I is processed exactly as if I was an instance field.
      • In caso contrario, il risultato è un accesso a eventi con un'espressione di istanza associata di E.Otherwise, the result is an event access with an associated instance expression of E.
  • In caso contrario, viene effettuato un tentativo di elaborare E.I come chiamata al metodo di estensione (chiamate al metodo di estensione).Otherwise, an attempt is made to process E.I as an extension method invocation (Extension method invocations). Se l'operazione ha esito negativo, E.I è un riferimento a un membro non valido e si verifica un errore in fase di binding.If this fails, E.I is an invalid member reference, and a binding-time error occurs.

Nomi semplici e nomi di tipi identiciIdentical simple names and type names

In un accesso ai membri del form E.I, se E è un identificatore singolo e se il significato di E come simple_name (nomi semplici) è una costante, un campo, una proprietà, una variabile locale o un parametro con lo stesso tipo del significato di E come type_name (nomi ditipo e spazio dei nomi), sono consentiti entrambi i significati di 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. I due possibili significati di E.I non sono mai ambigui perché I deve necessariamente essere un membro del tipo E in entrambi i casi.The two possible meanings of E.I are never ambiguous, since I must necessarily be a member of the type E in both cases. In altre parole, la regola consente semplicemente l'accesso ai membri statici e ai tipi annidati di E in cui si è verificato un errore in fase di compilazione.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. Ad esempio: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
    }
}

Ambiguità della grammaticaGrammar ambiguities

Le produzioni per simple_name (nomi semplici) e member_access (accesso ai membri) possono dare luogo a ambiguità nella grammatica per le espressioni.The productions for simple_name (Simple names) and member_access (Member access) can give rise to ambiguities in the grammar for expressions. Ad esempio, l'istruzione:For example, the statement:

F(G<A,B>(7));

può essere interpretato come una chiamata a F con due argomenti, G < A e B > (7).could be interpreted as a call to F with two arguments, G < A and B > (7). In alternativa, può essere interpretato come una chiamata a F con un argomento, ovvero una chiamata a un metodo generico G con due argomenti di tipo e un argomento normale.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.

Se una sequenza di token può essere analizzata (nel contesto) come simple_name (nomi semplici), member_access (accesso ai membri) o pointer_member_access (accesso al membro del puntatore) che termina con un type_argument_list (argomenti di tipo), il token che segue immediatamente il token di chiusura > viene esaminato.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. Se è uno deiIf it is one of

(  )  ]  }  :  ;  ,  .  ?  ==  !=  |  ^

la type_argument_list viene quindi mantenuta come parte del simple_name, member_access o pointer_member_access e qualsiasi altra possibile analisi della sequenza di token viene eliminata.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. In caso contrario, il type_argument_list non è considerato parte del simple_name, member_access o pointer_member_access, anche se non è possibile analizzare la sequenza di token.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. Si noti che queste regole non vengono applicate durante l'analisi di un type_argument_list in una namespace_or_type_name (nomi di spazio dei nomi e di tipo).Note that these rules are not applied when parsing a type_argument_list in a namespace_or_type_name (Namespace and type names). L'istruzioneThe statement

F(G<A,B>(7));

in base a questa regola, sarà interpretato come una chiamata a F con un argomento, ovvero una chiamata a un metodo generico G con due argomenti di tipo e un argomento normale.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. IstruzioniThe statements

F(G < A, B > 7);
F(G < A, B >> 7);

ogni oggetto verrà interpretato come una chiamata a F con due argomenti.will each be interpreted as a call to F with two arguments. L'istruzioneThe statement

x = F < A > +y;

verrà interpretato come un operatore minore di, un operatore maggiore di e un operatore unario più, come se l'istruzione fosse stata scritta x = (F < A) > (+y), anziché come simple_name con un type_argument_list seguito da un operatore binario più.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. Nell'istruzioneIn the statement

x = y is C<T> + z;

i token C<T> vengono interpretati come namespace_or_type_name con un type_argument_list.the tokens C<T> are interpreted as a namespace_or_type_name with a type_argument_list.

Espressioni di chiamataInvocation expressions

Viene usato un invocation_expression per richiamare un metodo.An invocation_expression is used to invoke a method.

invocation_expression
    : primary_expression '(' argument_list? ')'
    ;

Un invocation_expression è associato in modo dinamico (associazione dinamica) se è presente almeno uno dei seguenti elementi:An invocation_expression is dynamically bound (Dynamic binding) if at least one of the following holds:

  • Il primary_expression ha dynamicdi tipo in fase di compilazione.The primary_expression has compile-time type dynamic.
  • Almeno un argomento del argument_list facoltativo dispone del tipo in fase di compilazione dynamic e la primary_expression non dispone di un tipo delegato.At least one argument of the optional argument_list has compile-time type dynamic and the primary_expression does not have a delegate type.

In questo caso il compilatore classifica la invocation_expression come valore di tipo dynamic.In this case the compiler classifies the invocation_expression as a value of type dynamic. Le regole seguenti per determinare il significato della invocation_expression vengono quindi applicate in fase di esecuzione, usando il tipo di runtime anziché il tipo in fase di compilazione di quelli degli primary_expression e degli argomenti che hanno il tipo in fase di compilazione 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. Se il primary_expression non dispone di un tipo in fase di compilazione dynamic, la chiamata al metodo viene sottoposta a un controllo del tempo di compilazione limitato come descritto nel controllo della risoluzione dell'overload dinamico in fase dicompilazione.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.

Il primary_expression di un invocation_expression deve essere un gruppo di metodi o un valore di un delegate_type.The primary_expression of an invocation_expression must be a method group or a value of a delegate_type. Se il primary_expression è un gruppo di metodi, l' invocation_expression è una chiamata al metodo (chiamate al metodo).If the primary_expression is a method group, the invocation_expression is a method invocation (Method invocations). Se il primary_expression è un valore di un delegate_type, il invocation_expression è una chiamata al delegato (chiamate di delegati).If the primary_expression is a value of a delegate_type, the invocation_expression is a delegate invocation (Delegate invocations). Se il primary_expression non è né un gruppo di metodi né un valore di un delegate_type, si verifica un errore in fase di binding.If the primary_expression is neither a method group nor a value of a delegate_type, a binding-time error occurs.

Il argument_list facoltativo (elenchi di argomenti) fornisce valori o riferimenti a variabili per i parametri del metodo.The optional argument_list (Argument lists) provides values or variable references for the parameters of the method.

Il risultato della valutazione di un invocation_expression è classificato nel modo seguente:The result of evaluating an invocation_expression is classified as follows:

  • Se il invocation_expression richiama un metodo o un delegato che restituisce void, il risultato è Nothing.If the invocation_expression invokes a method or delegate that returns void, the result is nothing. Un'espressione classificata come Nothing è consentita solo nel contesto di un statement_expression (istruzioni Expression) o come il corpo di una lambda_expression (espressioni di funzione anonime).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). In caso contrario, si verifica un errore in fase di binding.Otherwise a binding-time error occurs.
  • In caso contrario, il risultato è un valore del tipo restituito dal metodo o dal delegato.Otherwise, the result is a value of the type returned by the method or delegate.

Chiamate al metodoMethod invocations

Per una chiamata al metodo, il primary_expression del invocation_expression deve essere un gruppo di metodi.For a method invocation, the primary_expression of the invocation_expression must be a method group. Il gruppo di metodi identifica il metodo da richiamare o il set di metodi di overload da cui scegliere un metodo specifico da richiamare.The method group identifies the one method to invoke or the set of overloaded methods from which to choose a specific method to invoke. Nel secondo caso, la determinazione del metodo specifico da richiamare si basa sul contesto fornito dai tipi degli argomenti nel 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.

L'elaborazione in fase di binding di una chiamata al metodo del form M(A), dove M è un gruppo di metodi (possibilmente incluso un type_argument_list) e A è un argument_listfacoltativo, è costituito dai passaggi seguenti: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:

  • Viene costruito il set di metodi candidati per la chiamata al metodo.The set of candidate methods for the method invocation is constructed. Per ogni metodo F associato al gruppo di metodi M:For each method F associated with the method group M:
    • Se F non è generico, F è un candidato nei casi seguenti:If F is non-generic, F is a candidate when:
    • Se F è generico e M non ha un elenco di argomenti di tipo, F è un candidato quando:If F is generic and M has no type argument list, F is a candidate when:
      • L'inferenza del tipo (inferenza del tipo) ha esito positivo, deducendo un elenco di argomenti di tipo per la chiamata eType inference (Type inference) succeeds, inferring a list of type arguments for the call, and
      • Una volta che gli argomenti di tipo dedotti vengono sostituiti con i parametri di tipo di metodo corrispondenti, tutti i tipi costruiti nell'elenco di parametri di F soddisfano i vincoli (vincoli di soddisfazione) e l'elenco di parametri di F è applicabile rispetto al A (membro della funzione applicabile).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 of F is applicable with respect to A (Applicable function member).
    • Se F è generico e M include un elenco di argomenti di tipo, F è un candidato nei casi seguenti:If F is generic and M includes a type argument list, F is a candidate when:
      • F ha lo stesso numero di parametri di tipo di metodo forniti nell'elenco di argomenti di tipo eF has the same number of method type parameters as were supplied in the type argument list, and
      • Una volta che gli argomenti di tipo vengono sostituiti con i parametri di tipo di metodo corrispondenti, tutti i tipi costruiti nell'elenco di parametri di F soddisfano i vincoli (vincoli di soddisfazione) e l'elenco di parametri di F è applicabile rispetto al A (membro della funzione applicabile).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 of F is applicable with respect to A (Applicable function member).
  • Il set di metodi candidati è ridotto in modo che contenga solo metodi dei tipi più derivati: per ogni metodo C.F nel set, dove C è il tipo in cui viene dichiarato il metodo F, tutti i metodi dichiarati in un tipo di base di C vengono rimossi dal set.The set of candidate methods is reduced to contain only methods from the most derived types: For each method C.F in the set, where C is the type in which the method F is declared, all methods declared in a base type of C are removed from the set. Inoltre, se C è un tipo di classe diverso da object, tutti i metodi dichiarati in un tipo di interfaccia vengono rimossi dal set.Furthermore, if C is a class type other than object, all methods declared in an interface type are removed from the set. Questa seconda regola ha effetto solo quando il gruppo di metodi è il risultato di una ricerca di membri su un parametro di tipo con una classe di base efficace diversa da Object e un set di interfacce effettive non vuote.(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.)
  • Se il set di metodi candidati risultante è vuoto, l'ulteriore elaborazione nei passaggi seguenti viene abbandonata e viene invece eseguito un tentativo di elaborare la chiamata come chiamata al metodo di estensione (chiamate almetodo di estensione).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). Se l'operazione ha esito negativo, non esiste alcun metodo applicabile e si verifica un errore in fase di binding.If this fails, then no applicable methods exist, and a binding-time error occurs.
  • Il metodo migliore del set di metodi candidati viene identificato mediante le regole di risoluzione dell'overload della risoluzione dell'overload.The best method of the set of candidate methods is identified using the overload resolution rules of Overload resolution. Se non è possibile identificare un singolo metodo migliore, la chiamata al metodo è ambigua e si verifica un errore in fase di binding.If a single best method cannot be identified, the method invocation is ambiguous, and a binding-time error occurs. Quando si esegue la risoluzione dell'overload, i parametri di un metodo generico vengono considerati dopo la sostituzione degli argomenti di tipo (forniti o dedotti) per i parametri di tipo di metodo corrispondenti.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.
  • Viene eseguita la convalida finale del metodo migliore scelto:Final validation of the chosen best method is performed:
    • Il metodo viene convalidato nel contesto del gruppo di metodi: se il metodo migliore è un metodo statico, il gruppo di metodi deve essere risultato da un simple_name o da un member_access tramite un tipo.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. Se il metodo migliore è un metodo di istanza, il gruppo di metodi deve essere risultato da un simple_name, un member_access tramite una variabile o un valore o un 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. Se nessuno di questi requisiti è true, si verifica un errore in fase di binding.If neither of these requirements is true, a binding-time error occurs.
    • Se il metodo migliore è un metodo generico, gli argomenti di tipo (forniti o dedotti) vengono controllati in base ai vincoli (vincoli di soddisfazione) dichiarati nel metodo generico.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. Se un argomento di tipo non soddisfa i vincoli corrispondenti nel parametro di tipo, si verificherà un errore in fase di binding.If any type argument does not satisfy the corresponding constraint(s) on the type parameter, a binding-time error occurs.

Una volta che un metodo è stato selezionato e convalidato in fase di binding con i passaggi precedenti, l'effettiva chiamata in fase di esecuzione viene elaborata in base alle regole della chiamata del membro della funzione descritta nel controllo della risoluzione dell'overload dinamico in fase di compilazione.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.

L'effetto intuitivo delle regole di risoluzione descritte in precedenza è il seguente: per individuare il metodo specifico richiamato da una chiamata al metodo, iniziare con il tipo indicato dalla chiamata al metodo e procedere alla catena di ereditarietà fino ad almeno uno applicabile, è stata trovata una dichiarazione di metodo accessibile e non di override.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. Eseguire quindi l'inferenza del tipo e la risoluzione dell'overload sul set di metodi applicabili, accessibili e non di override dichiarati in quel tipo e richiamare il metodo selezionato.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. Se non è stato trovato alcun metodo, provare invece a elaborare la chiamata come chiamata al metodo di estensione.If no method was found, try instead to process the invocation as an extension method invocation.

Chiamate al metodo di estensioneExtension method invocations

In una chiamata al metodo (chiamate sulle istanze boxed) di uno dei formIn a method invocation (Invocations on boxed instances) of one of the forms

expr . identifier ( )

expr . identifier ( args )

expr . identifier < typeargs > ( )

expr . identifier < typeargs > ( args )

Se la normale elaborazione della chiamata non trova metodi applicabili, viene effettuato un tentativo di elaborare il costrutto come una chiamata al metodo di estensione.if the normal processing of the invocation finds no applicable methods, an attempt is made to process the construct as an extension method invocation. Se expr o uno degli argomenti ha un tipo in fase di compilazione dynamic, i metodi di estensione non verranno applicati.If expr or any of the args has compile-time type dynamic, extension methods will not apply.

L'obiettivo è trovare il migliore type_name C, in modo che la chiamata al metodo statico corrispondente possa essere eseguita: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 )

Un metodo di estensione Ci.Mj è idoneo se:An extension method Ci.Mj is eligible if:

  • Ci è una classe non generica non annidataCi is a non-generic, non-nested class
  • Il nome del Mj è IdentifierThe name of Mj is identifier
  • Mj è accessibile e applicabile quando viene applicato agli argomenti come metodo statico, come illustrato in precedenza.Mj is accessible and applicable when applied to the arguments as a static method as shown above
  • Un'identità implicita, un riferimento o una conversione boxing esiste da expr al tipo del primo parametro di Mj.An implicit identity, reference or boxing conversion exists from expr to the type of the first parameter of Mj.

La ricerca di C procede come segue:The search for C proceeds as follows:

  • A partire dalla dichiarazione dello spazio dei nomi di inclusione più vicina, continuando con ogni dichiarazione dello spazio dei nomi di inclusione e terminando con l'unità di compilazione che lo contiene, vengono eseguiti tentativi successivi per trovare un set candidato di metodi di estensione: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:
    • Se lo spazio dei nomi o l'unità di compilazione specificata contiene direttamente dichiarazioni di tipo non generico Ci con i metodi di estensione idonei Mj, il set di tali metodi di estensione è il set candidato.If the given namespace or compilation unit directly contains non-generic type declarations Ci with eligible extension methods Mj, then the set of those extension methods is the candidate set.
    • Se i tipi Ci importati da using_static_declarations e dichiarati direttamente negli spazi dei nomi importati da using_namespace_directives nello spazio dei nomi o nell'unità di compilazione specificata contengono direttamente i metodi di estensione idonei Mj, il set di tali metodi di estensione è il set candidato.If types Ci imported by using_static_declarations and directly declared in namespaces imported by using_namespace_directives in the given namespace or compilation unit directly contain eligible extension methods Mj, then the set of those extension methods is the candidate set.
  • Se non viene trovato alcun set candidato in alcuna dichiarazione dello spazio dei nomi che lo contiene o in un'unità di compilazione, si verifica un errore in fase di compilazione.If no candidate set is found in any enclosing namespace declaration or compilation unit, a compile-time error occurs.
  • In caso contrario, la risoluzione dell'overload viene applicata al set candidato come descritto in (risoluzione dell'overload).Otherwise, overload resolution is applied to the candidate set as described in (Overload resolution). Se non viene trovato alcun metodo migliore, si verifica un errore in fase di compilazione.If no single best method is found, a compile-time error occurs.
  • C è il tipo in cui viene dichiarato il metodo migliore come metodo di estensione.C is the type within which the best method is declared as an extension method.

Utilizzando C come destinazione, la chiamata al metodo viene quindi elaborata come chiamata a un metodo statico (controllo della fase di compilazione della risoluzione dell'overload dinamico).Using C as a target, the method call is then processed as a static method invocation (Compile-time checking of dynamic overload resolution).

Le regole precedenti indicano che i metodi di istanza hanno la precedenza sui metodi di estensione, che i metodi di estensione disponibili nelle dichiarazioni dello spazio dei nomi interno hanno la precedenza sui metodi di estensione disponibili nelle dichiarazioni dello spazio dei nomi esterno e tale estensione i metodi dichiarati direttamente in uno spazio dei nomi hanno la precedenza sui metodi di estensione importati nello stesso spazio dei nomi con una direttiva namespace using.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. Ad esempio: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)
    }
}

Nell'esempio, il metodo di Bha la precedenza sul primo metodo di estensione e il metodo del Cha la precedenza su entrambi i metodi di estensione.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();
        }
    }
}

L'output di questo esempio è:The output of this example is:

E.F(1)
D.G(2)
C.H(3)

D.G ha la precedenza su C.Ge E.F ha la precedenza su D.F e C.F.D.G takes precedence over C.G, and E.F takes precedence over both D.F and C.F.

Chiamate di delegatiDelegate invocations

Per la chiamata di un delegato, il primary_expression di invocation_expression deve essere un valore di un delegate_type.For a delegate invocation, the primary_expression of the invocation_expression must be a value of a delegate_type. Inoltre, considerando il delegate_type come membro di funzione con lo stesso elenco di parametri del delegate_type, il delegate_type deve essere applicabile (membro della funzione applicabile) rispetto alla argument_list del 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.

L'elaborazione in fase di esecuzione di una chiamata al delegato del modulo D(A), dove D è un primary_expression di un delegate_type e A è un argument_listfacoltativo, è costituito dai passaggi seguenti: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 viene valutata.D is evaluated. Se questa valutazione causa un'eccezione, non vengono eseguiti altri passaggi.If this evaluation causes an exception, no further steps are executed.
  • Il valore di D viene verificato come valido.The value of D is checked to be valid. Se il valore di D è null, viene generata un'System.NullReferenceException e non vengono eseguiti altri passaggi.If the value of D is null, a System.NullReferenceException is thrown and no further steps are executed.
  • In caso contrario, D è un riferimento a un'istanza del delegato.Otherwise, D is a reference to a delegate instance. Le chiamate del membro della funzione (controllo della fase di compilazione della risoluzione dell'overload dinamico) vengono eseguite su ognuna delle entità chiamabili nell'elenco chiamate del delegato.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. Per le entità richiamabili costituite da un'istanza e da un metodo di istanza, l'istanza per la chiamata è l'istanza contenuta nell'entità chiamabile.For callable entities consisting of an instance and instance method, the instance for the invocation is the instance contained in the callable entity.

Accesso agli elementiElement access

Un element_access è costituito da un primary_no_array_creation_expression, seguito da un token "[", seguito da un argument_list, seguito da un 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. Il argument_list è costituito da uno o più argomenti, separati da virgole.The argument_list consists of one or more arguments, separated by commas.

element_access
    : primary_no_array_creation_expression '[' expression_list ']'
    ;

Il argument_list di un element_access non può contenere argomenti ref o out.The argument_list of an element_access is not allowed to contain ref or out arguments.

Un element_access è associato in modo dinamico (associazione dinamica) se è presente almeno uno dei seguenti elementi:An element_access is dynamically bound (Dynamic binding) if at least one of the following holds:

  • Il primary_no_array_creation_expression ha dynamicdi tipo in fase di compilazione.The primary_no_array_creation_expression has compile-time type dynamic.
  • Almeno un'espressione della argument_list ha un tipo in fase di compilazione dynamic e la primary_no_array_creation_expression non ha un tipo di matrice.At least one expression of the argument_list has compile-time type dynamic and the primary_no_array_creation_expression does not have an array type.

In questo caso il compilatore classifica la element_access come valore di tipo dynamic.In this case the compiler classifies the element_access as a value of type dynamic. Le regole seguenti per determinare il significato della element_access vengono quindi applicate in fase di esecuzione, usando il tipo di runtime anziché il tipo in fase di compilazione di quelle delle espressioni primary_no_array_creation_expression e argument_list che hanno il tipo in fase di compilazione 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. Se il primary_no_array_creation_expression non dispone di un tipo in fase di compilazione dynamic, l'accesso agli elementi subisce un controllo del tempo di compilazione limitato, come descritto in controllo in fase di compilazione della risoluzione dell'overload dinamico.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.

Se il primary_no_array_creation_expression di un element_access è un valore di un array_type, il element_access è un accesso alla matrice (accesso alla matrice).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). In caso contrario, il primary_no_array_creation_expression deve essere una variabile o un valore di una classe, uno struct o un tipo di interfaccia con uno o più membri dell'indicizzatore, nel qual caso l' element_access è un accesso all'indicizzatore (accesso all'indicizzatore).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).

Accesso a matriciArray access

Per l'accesso a una matrice, il primary_no_array_creation_expression di element_access deve essere un valore di un array_type.For an array access, the primary_no_array_creation_expression of the element_access must be a value of an array_type. Inoltre, la argument_list di un accesso alla matrice non può contenere argomenti denominati. Il numero di espressioni nel argument_list deve corrispondere a quello della array_typee ogni espressione deve essere di tipo int, uint, long, ulongo deve essere convertibile in modo implicito in uno o più di questi tipi.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.

Il risultato della valutazione di un accesso alla matrice è una variabile del tipo di elemento della matrice, ovvero l'elemento di matrice selezionato dai valori delle espressioni nel argument_list.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.

L'elaborazione in fase di esecuzione di un accesso alla matrice nel formato P[A], dove P è un primary_no_array_creation_expression di un array_type e A è un argument_listè costituito dai passaggi seguenti: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 viene valutata.P is evaluated. Se questa valutazione causa un'eccezione, non vengono eseguiti altri passaggi.If this evaluation causes an exception, no further steps are executed.
  • Le espressioni di indice della argument_list vengono valutate in ordine, da sinistra a destra.The index expressions of the argument_list are evaluated in order, from left to right. Dopo la valutazione di ogni espressione di indice, viene eseguita una conversione implicita (conversioni implicite) in uno dei seguenti tipi: 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. Viene scelto il primo tipo in questo elenco per cui è stata scelta una conversione implicita.The first type in this list for which an implicit conversion exists is chosen. Se, ad esempio, l'espressione dell'indice è di tipo short viene eseguita una conversione implicita in int, dal momento che le conversioni implicite da short a int e da short a long sono possibili.For instance, if the index expression is of type short then an implicit conversion to int is performed, since implicit conversions from short to int and from short to long are possible. Se la valutazione di un'espressione di indice o della successiva conversione implicita genera un'eccezione, non vengono valutate ulteriori espressioni di indice e non vengono eseguiti altri passaggi.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.
  • Il valore di P viene verificato come valido.The value of P is checked to be valid. Se il valore di P è null, viene generata un'System.NullReferenceException e non vengono eseguiti altri passaggi.If the value of P is null, a System.NullReferenceException is thrown and no further steps are executed.
  • Il valore di ogni espressione nel argument_list viene verificato rispetto ai limiti effettivi di ogni dimensione dell'istanza di matrice a cui fa riferimento P.The value of each expression in the argument_list is checked against the actual bounds of each dimension of the array instance referenced by P. Se uno o più valori non sono compresi nell'intervallo, viene generata un'System.IndexOutOfRangeException e non vengono eseguiti altri passaggi.If one or more values are out of range, a System.IndexOutOfRangeException is thrown and no further steps are executed.
  • Il percorso dell'elemento della matrice fornito dalle espressioni di indice viene calcolato e questo percorso diventa il risultato dell'accesso alla matrice.The location of the array element given by the index expression(s) is computed, and this location becomes the result of the array access.

Accesso all'indicizzatoreIndexer access

Per un accesso all'indicizzatore, il primary_no_array_creation_expression di element_access deve essere una variabile o un valore di una classe, uno struct o un tipo di interfaccia e questo tipo deve implementare uno o più indicizzatori applicabili rispetto al argument_list della element_access.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.

L'elaborazione in fase di binding di un indicizzatore ha accesso al form P[A], dove P è un primary_no_array_creation_expression di una classe, uno struct o un tipo di interfaccia Te A è un argument_listè costituito dai passaggi seguenti: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:

  • Il set di indicizzatori fornito da T viene costruito.The set of indexers provided by T is constructed. Il set è costituito da tutti gli indicizzatori dichiarati in T o da un tipo di base di T che non sono override dichiarazioni e sono accessibili nel contesto corrente (accesso ai membri).The set consists of all indexers declared in T or a base type of T that are not override declarations and are accessible in the current context (Member access).
  • Il set viene ridotto agli indicizzatori applicabili e non nascosti da altri indicizzatori.The set is reduced to those indexers that are applicable and not hidden by other indexers. Le regole seguenti vengono applicate a ogni indicizzatore S.I nel set, dove S è il tipo in cui viene dichiarata la I dell'indicizzatore:The following rules are applied to each indexer S.I in the set, where S is the type in which the indexer I is declared:
  • Se il set risultante di indicizzatori candidati è vuoto, non esiste alcun indicizzatore applicabile e si verifica un errore in fase di binding.If the resulting set of candidate indexers is empty, then no applicable indexers exist, and a binding-time error occurs.
  • Il migliore indicizzatore del set di indicizzatori candidati viene identificato usando le regole di risoluzione dell'overload della risoluzione dell'overload.The best indexer of the set of candidate indexers is identified using the overload resolution rules of Overload resolution. Se non è possibile identificare un singolo indicizzatore migliore, l'accesso dell'indicizzatore è ambiguo e si verifica un errore in fase di binding.If a single best indexer cannot be identified, the indexer access is ambiguous, and a binding-time error occurs.
  • Le espressioni di indice della argument_list vengono valutate in ordine, da sinistra a destra.The index expressions of the argument_list are evaluated in order, from left to right. Il risultato dell'elaborazione dell'accesso dell'indicizzatore è un'espressione classificata come accesso all'indicizzatore.The result of processing the indexer access is an expression classified as an indexer access. L'espressione di accesso all'indicizzatore fa riferimento all'indicizzatore determinato nel passaggio precedente e ha un'espressione di istanza associata di P e un elenco di argomenti associato di A.The indexer access expression references the indexer determined in the step above, and has an associated instance expression of P and an associated argument list of A.

A seconda del contesto in cui viene usato, un accesso all'indicizzatore causa la chiamata della funzione di accesso Get o della funzione di accesso set dell'indicizzatore.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. Se l'accesso dell'indicizzatore è la destinazione di un'assegnazione, viene richiamata la funzione di accesso set per assegnare un nuovo valore (assegnazione semplice).If the indexer access is the target of an assignment, the set accessor is invoked to assign a new value (Simple assignment). In tutti gli altri casi, viene richiamata la funzione di accesso get per ottenere il valore corrente (valori di espressioni).In all other cases, the get accessor is invoked to obtain the current value (Values of expressions).

Questo accessoThis access

Una THIS_ACCESS è costituita dal thisdi parole riservate.A this_access consists of the reserved word this.

this_access
    : 'this'
    ;

Una THIS_ACCESS è consentita solo nel blocco di un costruttore di istanza, un metodo di istanza o una funzione di accesso di istanza.A this_access is permitted only in the block of an instance constructor, an instance method, or an instance accessor. Ha uno dei significati seguenti:It has one of the following meanings:

  • Quando this viene utilizzato in un primary_expression all'interno di un costruttore di istanza di una classe, viene classificato come valore.When this is used in a primary_expression within an instance constructor of a class, it is classified as a value. Il tipo di valore è il tipo di istanza (il tipo di istanza) della classe in cui si verifica l'utilizzo e il valore è un riferimento all'oggetto che viene costruito.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.
  • Quando this viene usato in un primary_expression all'interno di un metodo di istanza o di una funzione di accesso dell'istanza di una classe, viene classificato come valore.When this is used in a primary_expression within an instance method or instance accessor of a class, it is classified as a value. Il tipo di valore è il tipo di istanza (il tipo di istanza) della classe in cui si verifica l'utilizzo e il valore è un riferimento all'oggetto per il quale è stato richiamato il metodo o la funzione di accesso.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.
  • Quando this viene utilizzato in un primary_expression all'interno di un costruttore di istanza di uno struct, viene classificato come variabile.When this is used in a primary_expression within an instance constructor of a struct, it is classified as a variable. Il tipo della variabile è il tipo di istanza (il tipo di istanza) dello struct in cui si verifica l'utilizzo e la variabile rappresenta lo struct costruito.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. La variabile this di un costruttore di istanza di uno struct si comporta esattamente come un parametro di out del tipo struct, in particolare questo significa che la variabile deve essere assegnata definitivamente in ogni percorso di esecuzione del costruttore di istanza.The this variable of an instance constructor of a struct behaves exactly the same as an out parameter of the struct type—in particular, this means that the variable must be definitely assigned in every execution path of the instance constructor.
  • Quando this viene usato in un primary_expression all'interno di un metodo di istanza o di una funzione di accesso dell'istanza di uno struct, viene classificato come variabile.When this is used in a primary_expression within an instance method or instance accessor of a struct, it is classified as a variable. Il tipo della variabile è il tipo di istanza (il tipo di istanza) dello struct in cui si verifica l'utilizzo.The type of the variable is the instance type (The instance type) of the struct within which the usage occurs.
    • Se il metodo o la funzione di accesso non è un iteratore (iteratori), la variabile this rappresenta lo struct per il quale è stato richiamato il metodo o la funzione di accesso e si comporta esattamente come un parametro di ref del tipo di struct.If the method or accessor is not an iterator (Iterators), the this variable represents the struct for which the method or accessor was invoked, and behaves exactly the same as a ref parameter of the struct type.
    • Se il metodo o la funzione di accesso è un iteratore, la variabile this rappresenta una copia dello struct per cui è stato richiamato il metodo o la funzione di accesso e si comporta esattamente come un parametro di valore del tipo struct.If the method or accessor is an iterator, the this 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.

L'uso di this in un primary_expression in un contesto diverso da quelli elencati in precedenza è un errore in fase di compilazione.Use of this in a primary_expression in a context other than the ones listed above is a compile-time error. In particolare, non è possibile fare riferimento a this in un metodo statico, una funzione di accesso a una proprietà statica o in un variable_initializer di una dichiarazione di campo.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.

Accesso di baseBase access

Un base_access è costituito dalla parola riservata base seguito da un token "." e da un identificatore o da un argument_list racchiuso tra parentesi quadre: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 ']'
    ;

Viene usato un base_access per accedere ai membri della classe di base che sono nascosti da membri denominati in modo analogo nella classe o nello struct corrente.A base_access is used to access base class members that are hidden by similarly named members in the current class or struct. Una base_access è consentita solo nel blocco di un costruttore di istanza, un metodo di istanza o una funzione di accesso di istanza.A base_access is permitted only in the block of an instance constructor, an instance method, or an instance accessor. Quando base.I si verifica in una classe o in uno struct, I deve indicare un membro della classe di base di tale classe o struct.When base.I occurs in a class or struct, I must denote a member of the base class of that class or struct. Analogamente, quando base[E] si verifica in una classe, è necessario che nella classe di base sia presente un indicizzatore applicabile.Likewise, when base[E] occurs in a class, an applicable indexer must exist in the base class.

Al momento dell'associazione, le espressioni base_access del form base.I e base[E] vengono valutate esattamente come se fossero scritte ((B)this).I e ((B)this)[E], dove B è la classe di base della classe o dello struct in cui si verifica il costrutto.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. Pertanto, base.I e base[E] corrispondono a this.I e this[E], tranne this viene visualizzato come un'istanza della classe di base.Thus, base.I and base[E] correspond to this.I and this[E], except this is viewed as an instance of the base class.

Quando un base_access fa riferimento a un membro di una funzione virtuale (un metodo, una proprietà o un indicizzatore), la determinazione del membro della funzione da richiamare in fase di esecuzione (controllo della fase di compilazione della risoluzione dell'overload dinamico) viene modificata.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. Il membro della funzione richiamato è determinato dalla ricerca dell'implementazione più derivata (metodi virtuali) del membro della funzione rispetto al B (anziché rispetto al tipo di runtime di this, come avviene normalmente in un accesso non di base).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). Pertanto, all'interno di un override di un membro della funzione virtual, è possibile utilizzare un base_access per richiamare l'implementazione ereditata del membro della funzione.Thus, within an override of a virtual function member, a base_access can be used to invoke the inherited implementation of the function member. Se il membro della funzione a cui fa riferimento un base_access è astratto, si verifica un errore in fase di binding.If the function member referenced by a base_access is abstract, a binding-time error occurs.

Operatori di incremento e decremento in forma suffissaPostfix increment and decrement operators

post_increment_expression
    : primary_expression '++'
    ;

post_decrement_expression
    : primary_expression '--'
    ;

L'operando di un'operazione di incremento o di decremento suffisso deve essere un'espressione classificata come variabile, un accesso a una proprietà o un accesso all'indicizzatore.The operand of a postfix increment or decrement operation must be an expression classified as a variable, a property access, or an indexer access. Il risultato dell'operazione è un valore dello stesso tipo dell'operando.The result of the operation is a value of the same type as the operand.

Se il primary_expression dispone del tipo in fase di compilazione dynamic quindi l'operatore è associato in modo dinamico (associazione dinamica), il post_increment_expression o post_decrement_expression dispone del tipo in fase di compilazione dynamic e le regole seguenti vengono applicate in fase di esecuzione utilizzando il tipo di runtime del 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.

Se l'operando di un'operazione di incremento o di decremento suffisso è un accesso a una proprietà o a un indicizzatore, la proprietà o l'indicizzatore deve avere sia una funzione di accesso get che una 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. In caso contrario, si verificherà un errore in fase di binding.If this is not the case, a binding-time error occurs.

Viene applicata la risoluzione dell'overload dell'operatore unario (risoluzione dell'overload dell'operatore unario) per selezionare l'implementazione di un operatore specifico.Unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Per i tipi seguenti sono disponibili gli operatori ++ e -- predefiniti: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimale qualsiasi tipo enum.Predefined ++ and -- operators exist for the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, and any enum type. Gli operatori ++ predefiniti restituiscono il valore prodotto aggiungendo 1 all'operando e gli operatori di -- predefiniti restituiscono il valore prodotto sottraendo 1 dall'operando.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 un contesto di checked, se il risultato di questa operazione di aggiunta o sottrazione non è compreso nell'intervallo del tipo di risultato e il tipo di risultato è un tipo integrale o un tipo enum, viene generata un'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.

L'elaborazione in fase di esecuzione di un'operazione di incremento o decremento suffisso nel formato x++ o x-- prevede i passaggi seguenti:The run-time processing of a postfix increment or decrement operation of the form x++ or x-- consists of the following steps:

  • If x is classified as a variable:If x is classified as a variable:
    • x is evaluated to produce the variable.x is evaluated to produce the variable.
    • Il valore di x viene salvato.The value of x is saved.
    • L'operatore selezionato viene richiamato con il valore salvato di x come argomento.The selected operator is invoked with the saved value of x as its argument.
    • Il valore restituito dall'operatore viene archiviato nella posizione specificata dalla valutazione del x.The value returned by the operator is stored in the location given by the evaluation of x.
    • Il valore salvato di x diventa il risultato dell'operazione.The saved value of x becomes the result of the operation.
  • Se x è classificato come accesso a una proprietà o a un indicizzatore:If x is classified as a property or indexer access:
    • L'espressione dell'istanza (se x non è static) e l'elenco di argomenti (se x è un accesso all'indicizzatore) associato a x vengono valutati e i risultati vengono utilizzati nelle chiamate successive get e set della funzione di accesso.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.
    • Viene richiamata la funzione di accesso get di x e viene salvato il valore restituito.The get accessor of x is invoked and the returned value is saved.
    • L'operatore selezionato viene richiamato con il valore salvato di x come argomento.The selected operator is invoked with the saved value of x as its argument.
    • Viene richiamata la funzione di accesso set di x con il valore restituito dall'operatore come argomento value.The set accessor of x is invoked with the value returned by the operator as its value argument.
    • Il valore salvato di x diventa il risultato dell'operazione.The saved value of x becomes the result of the operation.

Gli operatori ++ e -- supportano anche la notazione del prefisso (operatori di incremento e decremento del prefisso).The ++ and -- operators also support prefix notation (Prefix increment and decrement operators). In genere, il risultato di x++ o x-- è il valore di x prima dell'operazione, mentre il risultato di ++x o --x è il valore di x dopo l'operazione.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 entrambi i casi, x stesso ha lo stesso valore dopo l'operazione.In either case, x itself has the same value after the operation.

È possibile richiamare un'implementazione di operator ++ o operator -- utilizzando la notazione suffissa o prefisso.An operator ++ or operator -- implementation can be invoked using either postfix or prefix notation. Non è possibile avere implementazioni di operatori separate per le due notazioni.It is not possible to have separate operator implementations for the two notations.

Operatore newThe new operator

L'operatore new viene utilizzato per creare nuove istanze di tipi.The new operator is used to create new instances of types.

Sono disponibili tre forme di new espressioni:There are three forms of new expressions:

  • Le espressioni di creazione di oggetti vengono usate per creare nuove istanze di tipi di classe e tipi di valore.Object creation expressions are used to create new instances of class types and value types.
  • Le espressioni di creazione di matrici vengono usate per creare nuove istanze di tipi matrice.Array creation expressions are used to create new instances of array types.
  • Le espressioni di creazione dei delegati vengono usate per creare nuove istanze di tipi delegati.Delegate creation expressions are used to create new instances of delegate types.

L'operatore new implica la creazione di un'istanza di un tipo, ma non implica necessariamente l'allocazione dinamica della memoria.The new operator implies creation of an instance of a type, but does not necessarily imply dynamic allocation of memory. In particolare, le istanze di tipi valore non richiedono memoria aggiuntiva oltre le variabili in cui risiedono e non si verificano allocazioni dinamiche quando new viene utilizzato per creare istanze di tipi di valore.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.

Espressioni di creazione di oggettiObject creation expressions

Viene utilizzato un object_creation_expression per creare una nuova istanza di un class_type o di un 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
    ;

Il tipo di object_creation_expression deve essere un class_type, un value_type o un type_parameter.The type of an object_creation_expression must be a class_type, a value_type or a type_parameter. Il tipo non può essere un abstract class_type.The type cannot be an abstract class_type.

Il argument_list facoltativo (elenchi di argomenti) è consentito solo se il tipo è un class_type o un struct_type.The optional argument_list (Argument lists) is permitted only if the type is a class_type or a struct_type.

Un'espressione di creazione di oggetti può omettere l'elenco di argomenti del costruttore e racchiudere le parentesi purché includa un inizializzatore di oggetto o un inizializzatore di raccolta.An object creation expression can omit the constructor argument list and enclosing parentheses provided it includes an object initializer or collection initializer. Omettere l'elenco di argomenti del costruttore e le parentesi di inclusione equivale a specificare un elenco di argomenti vuoto.Omitting the constructor argument list and enclosing parentheses is equivalent to specifying an empty argument list.

L'elaborazione di un'espressione di creazione di oggetti che include un inizializzatore di oggetto o un inizializzatore di raccolta consiste nella prima elaborazione del costruttore di istanza e quindi nell'elaborazione delle inizializzazioni di membri o elementi specificate dall'inizializzatore di oggetto (inizializzatori di oggetto) o dall'inizializzatore di raccolta (inizializzatori di insieme).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).

Se uno degli argomenti nel argument_list facoltativo dispone del tipo in fase di compilazione dynamic il object_creation_expression è associato in modo dinamico (associazione dinamica) e le regole seguenti vengono applicate in fase di esecuzione utilizzando il tipo di runtime degli argomenti del argument_list con il tipo di tempo di compilazione 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. Tuttavia, la creazione dell'oggetto viene sottoposta a un controllo del tempo di compilazione limitato, come descritto in controllo in fase di compilazione della risoluzione dell'overload dinamico.However, the object creation undergoes a limited compile time check as described in Compile-time checking of dynamic overload resolution.

L'elaborazione in fase di binding di un object_creation_expression nel formato new T(A), in cui T è un class_type o un value_type e A è un argument_listfacoltativo, è costituito dai passaggi seguenti: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:

  • Se T è un value_type e A non è presente:If T is a value_type and A is not present:
    • Il object_creation_expression è una chiamata del costruttore predefinito.The object_creation_expression is a default constructor invocation. Il risultato della object_creation_expression è un valore di tipo T, vale a dire il valore predefinito per T come definito nel tipo System. ValueType.The result of the object_creation_expression is a value of type T, namely the default value for T as defined in The System.ValueType type.
  • In caso contrario, se T è un type_parameter e A non è presente:Otherwise, if T is a type_parameter and A is not present:
    • Se per Tnon è stato specificato alcun vincolo del tipo di valore o del costruttore (vincoli di parametro di tipo), si verifica un errore in fase di binding.If no value type constraint or constructor constraint (Type parameter constraints) has been specified for T, a binding-time error occurs.
    • Il risultato della object_creation_expression è un valore del tipo di runtime a cui è stato associato il parametro di tipo, ovvero il risultato della chiamata del costruttore predefinito di quel tipo.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. Il tipo in fase di esecuzione può essere un tipo riferimento o un tipo valore.The run-time type may be a reference type or a value type.
  • In caso contrario, se T è un class_type o un struct_type:Otherwise, if T is a class_type or a struct_type:
    • Se T è un abstract class_type, si verifica un errore in fase di compilazione.If T is an abstract class_type, a compile-time error occurs.
    • Il costruttore di istanza da richiamare viene determinato mediante le regole di risoluzione dell'overload della risoluzione dell'overload.The instance constructor to invoke is determined using the overload resolution rules of Overload resolution. Il set di costruttori di istanza candidati è costituito da tutti i costruttori di istanza accessibili dichiarati in T applicabili rispetto al A (membro della funzione applicabile).The set of candidate instance constructors consists of all accessible instance constructors declared in T which are applicable with respect to A (Applicable function member). Se il set di costruttori di istanza candidati è vuoto o se non è possibile identificare un singolo costruttore di istanze migliore, si verificherà un errore in fase di binding.If the set of candidate instance constructors is empty, or if a single best instance constructor cannot be identified, a binding-time error occurs.
    • Il risultato della object_creation_expression è un valore di tipo T, vale a dire il valore prodotto richiamando il costruttore di istanza determinato nel passaggio precedente.The result of the object_creation_expression is a value of type T, namely the value produced by invoking the instance constructor determined in the step above.
  • In caso contrario, il object_creation_expression non è valido e si verifica un errore in fase di binding.Otherwise, the object_creation_expression is invalid, and a binding-time error occurs.

Anche se il object_creation_expression è associato in modo dinamico, il tipo in fase di compilazione è ancora T.Even if the object_creation_expression is dynamically bound, the compile-time type is still T.

L'elaborazione in fase di esecuzione di un object_creation_expression nel formato new T(A), in cui T è class_type o struct_type e A è un argument_listfacoltativo, è costituito dai passaggi seguenti: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:

  • Se T è un class_type:If T is a class_type:
    • Viene allocata una nuova istanza della classe T.A new instance of class T is allocated. Se la memoria disponibile non è sufficiente per allocare la nuova istanza, viene generata un'System.OutOfMemoryException e non vengono eseguiti altri passaggi.If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.
    • Tutti i campi della nuova istanza vengono inizializzati sui relativi valori predefiniti (valori predefiniti).All fields of the new instance are initialized to their default values (Default values).
    • Il costruttore di istanza viene richiamato in base alle regole della chiamata del membro della funzione (controllo della fase di compilazione della risoluzione dell'overload dinamico).The instance constructor is invoked according to the rules of function member invocation (Compile-time checking of dynamic overload resolution). Un riferimento all'istanza appena allocata viene passato automaticamente al costruttore di istanza e l'istanza può essere accessibile dall'interno di tale costruttore come 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 as this.
  • Se T è un struct_type:If T is a struct_type:
    • Un'istanza di tipo T viene creata allocando una variabile locale temporanea.An instance of type T is created by allocating a temporary local variable. Poiché è necessario un costruttore di istanza di un struct_type per assegnare definitivamente un valore a ogni campo dell'istanza da creare, non è necessaria alcuna inizializzazione della variabile temporanea.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.
    • Il costruttore di istanza viene richiamato in base alle regole della chiamata del membro della funzione (controllo della fase di compilazione della risoluzione dell'overload dinamico).The instance constructor is invoked according to the rules of function member invocation (Compile-time checking of dynamic overload resolution). Un riferimento all'istanza appena allocata viene passato automaticamente al costruttore di istanza e l'istanza può essere accessibile dall'interno di tale costruttore come 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 as this.

Inizializzatori di oggettoObject initializers

Un inizializzatore di oggetto specifica i valori per zero o più campi, proprietà o elementi indicizzati di un oggetto.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
    ;

Un inizializzatore di oggetto è costituito da una sequenza di inizializzatori di membri, racchiusi tra { e token di } e separati da virgole.An object initializer consists of a sequence of member initializers, enclosed by { and } tokens and separated by commas. Ogni member_initializer designa una destinazione per l'inizializzazione.Each member_initializer designates a target for the initialization. Un identificatore deve denominare una proprietà o un campo accessibile dell'oggetto da inizializzare, mentre un argument_list racchiuso tra parentesi quadre deve specificare argomenti per un indicizzatore accessibile nell'oggetto da inizializzare.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. Un inizializzatore di oggetto può includere più di un inizializzatore di membro per lo stesso campo o proprietà.It is an error for an object initializer to include more than one member initializer for the same field or property.

Ogni initializer_target è seguita da un segno di uguale e da un'espressione, un inizializzatore di oggetto o un inizializzatore di raccolta.Each initializer_target is followed by an equals sign and either an expression, an object initializer or a collection initializer. Non è possibile che le espressioni all'interno dell'inizializzatore di oggetto facciano riferimento all'oggetto appena creato che sta inizializzando.It is not possible for expressions within the object initializer to refer to the newly created object it is initializing.

Un inizializzatore di membro che specifica un'espressione dopo il segno di uguale viene elaborato allo stesso modo di un'assegnazione (assegnazione semplice) alla destinazione.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.

Inizializzatore di membro che specifica un inizializzatore di oggetto dopo che il segno di uguale è un inizializzatore di oggetto annidato, ovvero un'inizializzazione di un oggetto incorporato.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. Anziché assegnare un nuovo valore al campo o alla proprietà, le assegnazioni nell'inizializzatore di oggetto annidato vengono considerate come assegnazioni ai membri del campo o della proprietà.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. Gli inizializzatori di oggetti annidati non possono essere applicati alle proprietà con un tipo di valore o a campi di sola lettura con un tipo di valore.Nested object initializers cannot be applied to properties with a value type, or to read-only fields with a value type.

Un inizializzatore di membro che specifica un inizializzatore di raccolta dopo il segno di uguale è un'inizializzazione di una raccolta incorporata.A member initializer that specifies a collection initializer after the equals sign is an initialization of an embedded collection. Anziché assegnare una nuova raccolta al campo di destinazione, alla proprietà o all'indicizzatore, gli elementi forniti nell'inizializzatore vengono aggiunti alla raccolta a cui fa riferimento la destinazione.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. La destinazione deve essere di un tipo di raccolta che soddisfa i requisiti specificati negli inizializzatori di insieme.The target must be of a collection type that satisfies the requirements specified in Collection initializers.

Gli argomenti di un inizializzatore di indice verranno sempre valutati esattamente una volta.The arguments to an index initializer will always be evaluated exactly once. Pertanto, anche se gli argomenti non vengono mai usati, ad esempio a causa di un inizializzatore nidificato vuoto, verranno valutati per gli effetti collaterali.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.

La classe seguente rappresenta un punto con due Coordinate: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; } }
}

È possibile creare e inizializzare un'istanza di Point come indicato di seguito:An instance of Point can be created and initialized as follows:

Point a = new Point { X = 0, Y = 1 };

che ha lo stesso effetto diwhich has the same effect as

Point __a = new Point();
__a.X = 0;
__a.Y = 1; 
Point a = __a;

dove __a è una variabile temporanea altrimenti invisibile e inaccessibile.where __a is an otherwise invisible and inaccessible temporary variable. La classe seguente rappresenta un rettangolo creato da due punti: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; } }
}

È possibile creare e inizializzare un'istanza di Rectangle come indicato di seguito: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 }
};

che ha lo stesso effetto diwhich 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;

dove __r, __p1 e __p2 sono variabili temporanee che altrimenti sono invisibili e inaccessibili.where __r, __p1 and __p2 are temporary variables that are otherwise invisible and inaccessible.

Se il costruttore di Rectanglealloca le due istanze di Point incorporateIf 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; } }
}

il costrutto seguente può essere usato per inizializzare le istanze di Point incorporate anziché assegnare nuove istanze: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 }
};

che ha lo stesso effetto diwhich 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;

Data la definizione appropriata di C, l'esempio seguente: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] = {}
};

equivale a questa serie di assegnazioni: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;

laddove __ce così via, vengono generate variabili che sono invisibili e inaccessibili al codice sorgente.where __c, etc., are generated variables that are invisible and inaccessible to the source code. Si noti che gli argomenti per [0,0] vengono valutati una sola volta e gli argomenti per [1,2] vengono valutati una sola volta, anche se non vengono mai utilizzati.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.

Inizializzatori di raccoltaCollection initializers

Un inizializzatore di raccolta specifica gli elementi di una raccolta.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)*
    ;

Un inizializzatore di raccolta è costituito da una sequenza di inizializzatori di elementi, racchiusi tra { e token di } e separati da virgole.A collection initializer consists of a sequence of element initializers, enclosed by { and } tokens and separated by commas. Ogni inizializzatore di elemento specifica un elemento da aggiungere all'oggetto della raccolta che viene inizializzato ed è costituito da un elenco di espressioni racchiuse tra { e } token e separate da virgole.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. Un inizializzatore di elemento a espressione singola può essere scritto senza parentesi graffe, ma non può essere quindi un'espressione di assegnazione, per evitare ambiguità con gli inizializzatori di membri.A single-expression element initializer can be written without braces, but cannot then be an assignment expression, to avoid ambiguity with member initializers. Il non_assignment_expression produzione è definito in Expression.The non_assignment_expression production is defined in Expression.

Di seguito è riportato un esempio di espressione di creazione di un oggetto che include un inizializzatore di raccolta: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 };

L'oggetto raccolta a cui è applicato un inizializzatore di raccolta deve essere di un tipo che implementa System.Collections.IEnumerable o si verifica un errore in fase di compilazione.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. Per ogni elemento specificato nell'ordine, l'inizializzatore di raccolta richiama un metodo di Add sull'oggetto di destinazione con l'elenco di espressioni dell'inizializzatore di elemento come elenco di argomenti, applicando la normale ricerca dei membri e la risoluzione dell'overload per ogni chiamata.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. Pertanto, l'oggetto raccolta deve avere un'istanza o un metodo di estensione applicabile con il nome Add per ogni inizializzatore di elemento.Thus, the collection object must have an applicable instance or extension method with the name Add for each element initializer.

La classe seguente rappresenta un contatto con un nome e un elenco di numeri di telefono: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; } }
}

È possibile creare e inizializzare un List<Contact> come indicato di seguito: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" }
    }
};

che ha lo stesso effetto diwhich 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;

dove __clist, __c1 e __c2 sono variabili temporanee che altrimenti sono invisibili e inaccessibili.where __clist, __c1 and __c2 are temporary variables that are otherwise invisible and inaccessible.

Espressioni di creazione di matriciArray creation expressions

Viene utilizzato un array_creation_expression per creare una nuova istanza di un 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
    ;

Un'espressione di creazione di matrici del primo form alloca un'istanza di matrice del tipo risultante dall'eliminazione di ognuna delle singole espressioni dall'elenco di espressioni.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. Ad esempio, l'espressione di creazione della matrice new int[10,20] produce un'istanza di matrice di tipo int[,]e l'espressione di creazione della matrice new int[10][,] produce una matrice di tipo 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[][,]. Ogni espressione nell'elenco di espressioni deve essere di tipo int, uint, longo ulongo convertibile in modo implicito in uno o più di questi tipi.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. Il valore di ogni espressione determina la lunghezza della dimensione corrispondente nell'istanza della matrice appena allocata.The value of each expression determines the length of the corresponding dimension in the newly allocated array instance. Poiché la lunghezza di una dimensione di matrice deve essere non negativa, si tratta di un errore in fase di compilazione con un constant_expression con un valore negativo nell'elenco di espressioni.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.

Ad eccezione di un contesto non sicuro (contesti non sicuri), il layout delle matrici non è specificato.Except in an unsafe context (Unsafe contexts), the layout of arrays is unspecified.

Se un'espressione di creazione di matrici del primo form include un inizializzatore di matrice, ogni espressione nell'elenco di espressioni deve essere una costante e le lunghezze e le lunghezze delle dimensioni specificate dall'elenco di espressioni devono corrispondere a quelle dell'inizializzatore di matrice.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 un'espressione di creazione di matrici della seconda o della terza forma, il rango del tipo di matrice o dell'identificatore di rango specificato deve corrispondere a quello dell'inizializzatore di matrice.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. Le singole lunghezze delle dimensioni vengono dedotte dal numero di elementi in ciascuno dei livelli di annidamento corrispondenti dell'inizializzatore di matrice.The individual dimension lengths are inferred from the number of elements in each of the corresponding nesting levels of the array initializer. Quindi, l'espressioneThus, the expression

new int[,] {{0, 1}, {2, 3}, {4, 5}}

corrisponde esattamente aexactly corresponds to

new int[3, 2] {{0, 1}, {2, 3}, {4, 5}}

Un'espressione di creazione di matrici del terzo form viene definita espressione di creazione di una matrice tipizzata in modo implicito.An array creation expression of the third form is referred to as an implicitly typed array creation expression. È simile al secondo formato, ad eccezione del fatto che il tipo di elemento della matrice non viene specificato in modo esplicito, ma è determinato come il tipo comune migliore (ricerca del tipo comune migliore di un set di espressioni) del set di espressioni nell'inizializzatore di matrice.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. Per una matrice multidimensionale, ad esempio una in cui il rank_specifier contiene almeno una virgola, questo set comprende tutte le espressionipresenti in array_initializerannidate.For a multidimensional array, i.e., one where the rank_specifier contains at least one comma, this set comprises all expressions found in nested array_initializers.

Gli inizializzatori di matrice sono descritti ulteriormente negli inizializzatori di matrice.Array initializers are described further in Array initializers.

Il risultato della valutazione di un'espressione di creazione di matrici è classificato come valore, ovvero un riferimento all'istanza di matrice appena allocata.The result of evaluating an array creation expression is classified as a value, namely a reference to the newly allocated array instance. L'elaborazione in fase di esecuzione di un'espressione di creazione di matrici prevede i passaggi seguenti:The run-time processing of an array creation expression consists of the following steps:

  • Le espressioni di lunghezza della dimensione della expression_list vengono valutate in ordine, da sinistra a destra.The dimension length expressions of the expression_list are evaluated in order, from left to right. Dopo la valutazione di ogni espressione, viene eseguita una conversione implicita (conversioni implicite) a uno dei seguenti tipi: 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. Viene scelto il primo tipo in questo elenco per cui è stata scelta una conversione implicita.The first type in this list for which an implicit conversion exists is chosen. Se la valutazione di un'espressione o della successiva conversione implicita genera un'eccezione, non vengono valutate altre espressioni e non vengono eseguiti altri passaggi.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.
  • I valori calcolati per le lunghezze delle dimensioni vengono convalidati come indicato di seguito.The computed values for the dimension lengths are validated as follows. Se uno o più valori sono minori di zero, viene generata un'System.OverflowException e non vengono eseguiti altri passaggi.If one or more of the values are less than zero, a System.OverflowException is thrown and no further steps are executed.
  • Viene allocata un'istanza di matrice con le lunghezze delle dimensioni specificate.An array instance with the given dimension lengths is allocated. Se la memoria disponibile non è sufficiente per allocare la nuova istanza, viene generata un'System.OutOfMemoryException e non vengono eseguiti altri passaggi.If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.
  • Tutti gli elementi della nuova istanza della matrice vengono inizializzati sui relativi valori predefiniti (valori predefiniti).All elements of the new array instance are initialized to their default values (Default values).
  • Se l'espressione di creazione della matrice contiene un inizializzatore di matrice, ogni espressione nell'inizializzatore di matrice viene valutata e assegnata all'elemento della matrice corrispondente.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. Le valutazioni e le assegnazioni vengono eseguite nell'ordine in cui le espressioni vengono scritte nell'inizializzatore di matrice. in altre parole, gli elementi vengono inizializzati in ordine di indice crescente, con la dimensione più a destra che aumenta per prima.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. Se la valutazione di un'espressione specificata o l'assegnazione successiva all'elemento della matrice corrispondente genera un'eccezione, non vengono inizializzati altri elementi (e gli elementi rimanenti avranno quindi i valori predefiniti).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).

Un'espressione di creazione di matrici consente di creare un'istanza di una matrice con elementi di un tipo matrice, ma gli elementi di tale matrice devono essere inizializzati manualmente.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. Ad esempio, l'istruzioneFor example, the statement

int[][] a = new int[100][];

Crea una matrice unidimensionale con 100 elementi di tipo int[].creates a single-dimensional array with 100 elements of type int[]. Il valore iniziale di ogni elemento è null.The initial value of each element is null. Per la stessa espressione di creazione della matrice non è possibile creare anche un'istanza delle sottomatrici e l'istruzioneIt 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

genera un errore in fase di compilazione.results in a compile-time error. La creazione di istanze delle sottomatrici deve invece essere eseguita manualmente, come inInstantiation 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];

Quando una matrice di matrici ha una forma "rettangolare", ovvero quando le sottomatrici hanno la stessa lunghezza, è più efficiente usare una matrice multidimensionale.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. Nell'esempio precedente, la creazione di un'istanza della matrice di matrici crea oggetti 101, ovvero una matrice esterna e 100 sottomatrici.In the example above, instantiation of the array of arrays creates 101 objects—one outer array and 100 sub-arrays. Al contrario,In contrast,

int[,] = new int[100, 5];

consente di creare un solo oggetto, una matrice bidimensionale e di eseguire l'allocazione in un'unica istruzione.creates only a single object, a two-dimensional array, and accomplishes the allocation in a single statement.

Di seguito sono riportati alcuni esempi di espressioni di creazione di matrici tipizzate in modo implicito: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

L'ultima espressione causa un errore in fase di compilazione perché né intstring sono convertibili in modo implicito nell'altro, quindi non esiste alcun tipo comune migliore.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. In questo caso, è necessario usare un'espressione di creazione di matrici tipizzata in modo esplicito, ad esempio specificando il tipo da object[].An explicitly typed array creation expression must be used in this case, for example specifying the type to be object[]. In alternativa, è possibile eseguire il cast di uno degli elementi in un tipo di base comune, che diventerebbe quindi il tipo di elemento derivato.Alternatively, one of the elements can be cast to a common base type, which would then become the inferred element type.

È possibile combinare espressioni di creazione di matrici tipizzate in modo implicito con inizializzatori di oggetti anonimi (espressioni di creazione di oggetti anonimi) per creare strutture di dati tipizzate anonimamente.Implicitly typed array creation expressions can be combined with anonymous object initializers (Anonymous object creation expressions) to create anonymously typed data structures. Ad esempio: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" }
    }
};

Espressioni di creazione di delegatiDelegate creation expressions

Viene utilizzato un delegate_creation_expression per creare una nuova istanza di un delegate_type.A delegate_creation_expression is used to create a new instance of a delegate_type.

delegate_creation_expression
    : 'new' delegate_type '(' expression ')'
    ;

L'argomento di un'espressione di creazione del delegato deve essere un gruppo di metodi, una funzione anonima o un valore del tipo di tempo di compilazione dynamic o una 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. Se l'argomento è un gruppo di metodi, identifica il metodo e, per un metodo di istanza, l'oggetto per il quale creare un delegato.If the argument is a method group, it identifies the method and, for an instance method, the object for which to create a delegate. Se l'argomento è una funzione anonima, definisce direttamente i parametri e il corpo del metodo della destinazione del delegato.If the argument is an anonymous function it directly defines the parameters and method body of the delegate target. Se l'argomento è un valore, identifica un'istanza di delegato di cui creare una copia.If the argument is a value it identifies a delegate instance of which to create a copy.

Se per l' espressione è dynamicil tipo in fase di compilazione, il delegate_creation_expression è associato in modo dinamico (associazione dinamica) e le regole seguenti vengono applicate in fase di esecuzione utilizzando il tipo di runtime dell' espressione.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. In caso contrario, le regole vengono applicate in fase di compilazione.Otherwise the rules are applied at compile-time.

L'elaborazione in fase di binding di un delegate_creation_expression nel formato new D(E), in cui D è un delegate_type e E è un' espressione, è costituita dai passaggi seguenti: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:

  • Se E è un gruppo di metodi, l'espressione di creazione del delegato viene elaborata in modo analogo alla conversione di un gruppo di metodi (conversioni di gruppi di metodi) da E a D.If E is a method group, the delegate creation expression is processed in the same way as a method group conversion (Method group conversions) from E to D.
  • Se E è una funzione anonima, l'espressione di creazione del delegato viene elaborata allo stesso modo di una conversione di funzione anonima (conversioni di funzioni anonime) da E a D.If E is an anonymous function, the delegate creation expression is processed in the same way as an anonymous function conversion (Anonymous function conversions) from E to D.
  • Se E è un valore, E deve essere compatibile (dichiarazioni delegate) con De il risultato è un riferimento a un delegato appena creato di tipo D che fa riferimento allo stesso elenco di chiamate di E.If E is a value, E must be compatible (Delegate declarations) with D, and the result is a reference to a newly created delegate of type D that refers to the same invocation list as E. Se E non è compatibile con D, si verifica un errore in fase di compilazione.If E is not compatible with D, a compile-time error occurs.

L'elaborazione in fase di esecuzione di un delegate_creation_expression nel formato new D(E), in cui D è un delegate_type e E è un' espressione, è costituita dai passaggi seguenti: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:

  • Se E è un gruppo di metodi, l'espressione di creazione del delegato viene valutata come conversione di un gruppo di metodi (conversioni di gruppi di metodi) da E a D.If E is a method group, the delegate creation expression is evaluated as a method group conversion (Method group conversions) from E to D.
  • Se E è una funzione anonima, la creazione del delegato viene valutata come conversione di funzione anonima da E a D (conversioni di funzioni anonime).If E is an anonymous function, the delegate creation is evaluated as an anonymous function conversion from E to D (Anonymous function conversions).
  • Se E è un valore di un delegate_type:If E is a value of a delegate_type:
    • E viene valutata.E is evaluated. Se questa valutazione causa un'eccezione, non vengono eseguiti altri passaggi.If this evaluation causes an exception, no further steps are executed.
    • Se il valore di E è null, viene generata un'System.NullReferenceException e non vengono eseguiti altri passaggi.If the value of E is null, a System.NullReferenceException is thrown and no further steps are executed.
    • Viene allocata una nuova istanza del tipo delegato D.A new instance of the delegate type D is allocated. Se la memoria disponibile non è sufficiente per allocare la nuova istanza, viene generata un'System.OutOfMemoryException e non vengono eseguiti altri passaggi.If there is not enough memory available to allocate the new instance, a System.OutOfMemoryException is thrown and no further steps are executed.
    • La nuova istanza del delegato viene inizializzata con lo stesso elenco chiamate dell'istanza del delegato fornita da E.The new delegate instance is initialized with the same invocation list as the delegate instance given by E.

L'elenco chiamate di un delegato viene determinato quando viene creata un'istanza del delegato e quindi rimane costante per l'intera durata del delegato.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 altre parole, non è possibile modificare le entità chiamabili di destinazione di un delegato dopo che è stato creato.In other words, it is not possible to change the target callable entities of a delegate once it has been created. Quando due delegati vengono combinati o uno viene rimosso da un altro (dichiarazioni di delegati), viene restituito un nuovo delegato. nessun delegato esistente ne è stato modificato il contenuto.When two delegates are combined or one is removed from another (Delegate declarations), a new delegate results; no existing delegate has its contents changed.

Non è possibile creare un delegato che fa riferimento a una proprietà, un indicizzatore, un operatore definito dall'utente, un costruttore di istanza, un distruttore o un costruttore statico.It is not possible to create a delegate that refers to a property, indexer, user-defined operator, instance constructor, destructor, or static constructor.

Come descritto in precedenza, quando viene creato un delegato da un gruppo di metodi, l'elenco di parametri formali e il tipo restituito del delegato determinano quale dei metodi di overload selezionare.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. Nell'esempioIn 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;
    }
}

il campo A.f viene inizializzato con un delegato che fa riferimento al secondo metodo Square perché il metodo corrisponde esattamente all'elenco di parametri formali e al tipo restituito di 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. Se il secondo Square metodo non fosse presente, si è verificato un errore in fase di compilazione.Had the second Square method not been present, a compile-time error would have occurred.

Espressioni di creazione di oggetti anonimiAnonymous object creation expressions

Viene utilizzato un anonymous_object_creation_expression per creare un oggetto di tipo anonimo.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
    ;

Un inizializzatore di oggetto anonimo dichiara un tipo anonimo e restituisce un'istanza di quel tipo.An anonymous object initializer declares an anonymous type and returns an instance of that type. Un tipo anonimo è un tipo di classe senza nome che eredita direttamente da object.An anonymous type is a nameless class type that inherits directly from object. I membri di un tipo anonimo sono una sequenza di proprietà di sola lettura dedotte dall'inizializzatore di oggetto anonimo utilizzato per creare un'istanza del tipo.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. In particolare, un inizializzatore di oggetto anonimo nel formatoSpecifically, an anonymous object initializer of the form

new { p1 = e1, p2 = e2, ..., pn = en }

dichiara un tipo anonimo del formdeclares 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() { ... }
}

dove ogni Tx è il tipo dell'espressione corrispondente ex.where each Tx is the type of the corresponding expression ex. L'espressione utilizzata in un member_declarator deve avere un tipo.The expression used in a member_declarator must have a type. Quindi, si tratta di un errore in fase di compilazione per un'espressione in un member_declarator essere null o una funzione anonima.Thus, it is a compile-time error for an expression in a member_declarator to be null or an anonymous function. Si tratta inoltre di un errore in fase di compilazione per l'espressione di un tipo unsafe.It is also a compile-time error for the expression to have an unsafe type.

I nomi di un tipo anonimo e del parametro al relativo metodo di Equals vengono generati automaticamente dal compilatore e non è possibile farvi riferimento nel testo del programma.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.

All'interno dello stesso programma, due inizializzatori di oggetti anonimi che specificano una sequenza di proprietà con gli stessi nomi e tipi in fase di compilazione nello stesso ordine produrranno istanze dello stesso tipo anonimo.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.

Nell'esempioIn the example

var p1 = new { Name = "Lawnmower", Price = 495.00 };
var p2 = new { Name = "Shovel", Price = 26.95 };
p1 = p2;

l'assegnazione sull'ultima riga è consentita perché p1 e p2 sono dello stesso tipo anonimo.the assignment on the last line is permitted because p1 and p2 are of the same anonymous type.

I metodi Equals e GetHashcode sui tipi anonimi eseguono l'override dei metodi ereditati da objecte sono definiti in termini di Equals e GetHashcode delle proprietà, in modo che due istanze dello stesso tipo anonimo siano uguali solo se tutte le relative proprietà sono uguali.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.

Un dichiaratore di membro può essere abbreviato in un nome semplice (inferenza del tipo), un accesso ai membri (controllo della fase di compilazione della risoluzione dell'overload dinamico), un accesso di base (accesso di base) o un accesso ai membri condizionali null (espressioni condizionali null come inizializzatori di proiezione).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). Si tratta di un inizializzatore di proiezione ed è una sintassi abbreviata per una dichiarazione di e l'assegnazione a una proprietà con lo stesso nome.This is called a projection initializer and is shorthand for a declaration of and assignment to a property with the same name. In particolare, dichiaratori di membri dei formSpecifically, member declarators of the forms

identifier
expr.identifier

sono esattamente equivalenti rispettivamente a quanto segue:are precisely equivalent to the following, respectively:

identifier = identifier
identifier = expr.identifier

Quindi, in un inizializzatore di proiezione l' identificatore seleziona sia il valore che il campo o la proprietà a cui è assegnato il valore.Thus, in a projection initializer the identifier selects both the value and the field or property to which the value is assigned. In modo intuitivo, un inizializzatore di proiezione proietta non solo un valore, ma anche il nome del valore.Intuitively, a projection initializer projects not just a value, but also the name of the value.

Operatore typeofThe typeof operator

L'operatore typeof viene usato per ottenere l'oggetto System.Type per un tipo.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
    : ','
    ;

La prima forma di typeof_expression è costituita da una parola chiave typeof seguita da un tiporacchiuso tra parentesi.The first form of typeof_expression consists of a typeof keyword followed by a parenthesized type. Il risultato di un'espressione di questo form è l'oggetto System.Type per il tipo indicato.The result of an expression of this form is the System.Type object for the indicated type. Esiste un solo oggetto System.Type per qualsiasi tipo specificato.There is only one System.Type object for any given type. Ciò significa che per un tipo T, typeof(T) == typeof(T) è sempre true.This means that for a type T, typeof(T) == typeof(T) is always true. Il tipo non può essere dynamic.The type cannot be dynamic.

La seconda forma di typeof_expression è costituita da una parola chiave typeof seguita da un unbound_type_nametra parentesi.The second form of typeof_expression consists of a typeof keyword followed by a parenthesized unbound_type_name. Una unbound_type_name è molto simile a una type_name (nomi di spazio dei nomi e di tipo), ad eccezione del fatto che un unbound_type_name contiene generic_dimension_specifiers dove un type_name contiene type_argument_lists.An unbound_type_name is very similar to a type_name (Namespace and type names) except that an unbound_type_name contains generic_dimension_specifiers where a type_name contains type_argument_lists. Quando l'operando di un typeof_expression è una sequenza di token che soddisfa le grammatiche di unbound_type_name e type_name, ovvero quando non contiene né un generic_dimension_specifier né un type_argument_list, la sequenza di token viene considerata come 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. Il significato di un unbound_type_name viene determinato nel modo seguente:The meaning of an unbound_type_name is determined as follows:

  • Converte la sequenza di token in un type_name sostituendo ogni generic_dimension_specifier con un type_argument_list con lo stesso numero di virgole e la parola chiave object come ogni type_argument.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 keyword object as each type_argument.
  • Valutare l' type_namerisultante, ignorando tutti i vincoli di parametro di tipo.Evaluate the resulting type_name, while ignoring all type parameter constraints.
  • Il unbound_type_name viene risolto nel tipo generico non associato associato al tipo costruito risultante (tipi associati e non associati).The unbound_type_name resolves to the unbound generic type associated with the resulting constructed type (Bound and unbound types).

Il risultato della typeof_expression è l'oggetto System.Type per il tipo generico non associato risultante.The result of the typeof_expression is the System.Type object for the resulting unbound generic type.

La terza forma di typeof_expression è costituita da una parola chiave typeof seguita da una parola chiave void tra parentesi.The third form of typeof_expression consists of a typeof keyword followed by a parenthesized void keyword. Il risultato di un'espressione di questo form è l'oggetto System.Type che rappresenta l'assenza di un tipo.The result of an expression of this form is the System.Type object that represents the absence of a type. L'oggetto tipo restituito da typeof(void) è diverso dall'oggetto tipo restituito per qualsiasi tipo.The type object returned by typeof(void) is distinct from the type object returned for any type. Questo oggetto di tipo speciale è utile nelle librerie di classi che consentono la reflection sui metodi nel linguaggio, in cui tali metodi vogliono avere un modo per rappresentare il tipo restituito di qualsiasi metodo, inclusi i metodi void, con un'istanza di 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.

L'operatore typeof può essere utilizzato in un parametro di tipo.The typeof operator can be used on a type parameter. Il risultato è l'oggetto System.Type per il tipo in fase di esecuzione associato al parametro di tipo.The result is the System.Type object for the run-time type that was bound to the type parameter. L'operatore typeof può essere usato anche in un tipo costruito o in un tipo generico non associato (tipi associati e non associati).The typeof operator can also be used on a constructed type or an unbound generic type (Bound and unbound types). L'oggetto System.Type per un tipo generico non associato è diverso dall'oggetto System.Type del tipo di istanza.The System.Type object for an unbound generic type is not the same as the System.Type object of the instance type. Il tipo di istanza è sempre un tipo costruito chiuso in fase di esecuzione, in modo che il relativo System.Type oggetto dipenda dagli argomenti di tipo runtime in uso, mentre il tipo generico non associato non dispone di argomenti di tipo.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.

EsempioThe 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();
    }
}

produce l'output seguente: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]

Si noti che int e System.Int32 sono dello stesso tipo.Note that int and System.Int32 are the same type.

Si noti inoltre che il risultato di typeof(X<>) non dipende dall'argomento di tipo, ma dal risultato di 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.

Operatori Checked e UncheckedThe checked and unchecked operators

Gli operatori checked e unchecked vengono utilizzati per controllare il contesto di controllo dell'overflow per le conversioni e le operazioni aritmetiche di tipo integrale.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 ')'
    ;

L'operatore checked valuta l'espressione contenuta in un contesto controllato e l'operatore unchecked valuta l'espressione contenuta in un contesto non controllato.The checked operator evaluates the contained expression in a checked context, and the unchecked operator evaluates the contained expression in an unchecked context. Un checked_expression o unchecked_expression corrisponde esattamente a un parenthesized_expression (espressioni racchiuse tra parentesi), ad eccezione del fatto che l'espressione contenuta viene valutata nel contesto di controllo dell'overflow specificato.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.

Il contesto di controllo dell'overflow può essere controllato anche tramite le istruzioni checked e unchecked (le istruzioni checked e unchecked).The overflow checking context can also be controlled through the checked and unchecked statements (The checked and unchecked statements).

Le operazioni seguenti sono interessate dal contesto di controllo dell'overflow stabilito dal checked e unchecked operatori e istruzioni:The following operations are affected by the overflow checking context established by the checked and unchecked operators and statements:

Quando una delle operazioni precedenti produce un risultato troppo grande per essere rappresentato nel tipo di destinazione, il contesto in cui viene eseguita l'operazione Controlla il comportamento risultante: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:

  • In un contesto di checked, se l'operazione è un'espressione costante (espressioni costanti), si verifica un errore in fase di compilazione.In a checked context, if the operation is a constant expression (Constant expressions), a compile-time error occurs. In caso contrario, quando l'operazione viene eseguita in fase di esecuzione, viene generata un'System.OverflowException.Otherwise, when the operation is performed at run-time, a System.OverflowException is thrown.
  • In un contesto di unchecked, il risultato viene troncato eliminando eventuali bit di ordine superiore che non rientrano nel tipo di destinazione.In an unchecked context, the result is truncated by discarding any high-order bits that do not fit in the destination type.

Per le espressioni non costanti (espressioni che vengono valutate in fase di esecuzione) che non sono racchiuse tra checked o operatori unchecked o istruzioni, il contesto di controllo dell'overflow predefinito viene unchecked a meno che i fattori esterni, ad esempio le opzioni del compilatore e la configurazione dell'ambiente di esecuzione, chiamino per la valutazione 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.

Per le espressioni costanti (espressioni che possono essere valutate completamente in fase di compilazione), il contesto di controllo dell'overflow predefinito è sempre checked.For constant expressions (expressions that can be fully evaluated at compile-time), the default overflow checking context is always checked. A meno che un'espressione costante non venga inserita in modo esplicito in un contesto di unchecked, i flussi che si verificano durante la valutazione in fase di compilazione dell'espressione provocano sempre errori in fase di compilazione.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.

Il corpo di una funzione anonima non è influenzato dai contesti di checked o unchecked in cui si verifica la funzione anonima.The body of an anonymous function is not affected by checked or unchecked contexts in which the anonymous function occurs.

Nell'esempioIn 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
    }
}

non vengono segnalati errori in fase di compilazione perché nessuna delle espressioni può essere valutata in fase di compilazione.no compile-time errors are reported since neither of the expressions can be evaluated at compile-time. In fase di esecuzione, il metodo F genera un'System.OverflowExceptione il metodo G restituisce-727379968 (i 32 bit inferiori del risultato fuori intervallo).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). Il comportamento del H metodo dipende dal contesto di controllo dell'overflow predefinito per la compilazione, ma è uguale F o uguale a 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.

Nell'esempioIn 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
    }
}

gli overflow che si verificano durante la valutazione delle espressioni costanti in F e H causare la segnalazione degli errori in fase di compilazione perché le espressioni vengono valutate in un contesto di 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. Si verifica un overflow anche durante la valutazione dell'espressione costante in G, ma poiché la valutazione viene eseguita in un contesto di unchecked, l'overflow non viene segnalato.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.

Gli operatori checked e unchecked hanno effetto solo sul contesto di controllo dell'overflow per le operazioni che sono contenute testualmente nei token "(" e ")".The checked and unchecked operators only affect the overflow checking context for those operations that are textually contained within the "(" and ")" tokens. Gli operatori non hanno alcun effetto sui membri di funzione richiamati come risultato della valutazione dell'espressione contenuta.The operators have no effect on function members that are invoked as a result of evaluating the contained expression. Nell'esempioIn the example

class Test
{
    static int Multiply(int x, int y) {
        return x * y;
    }

    static int F() {
        return checked(Multiply(1000000, 1000000));
    }
}

l'uso di checked in F non influisce sulla valutazione di x * y in Multiply, pertanto x * y viene valutato nel contesto di controllo dell'overflow predefinito.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.

L'operatore unchecked è utile per la scrittura di costanti dei tipi integrali con segno in notazione esadecimale.The unchecked operator is convenient when writing constants of the signed integral types in hexadecimal notation. Ad esempio:For example:

class Test
{
    public const int AllBits = unchecked((int)0xFFFFFFFF);

    public const int HighBit = unchecked((int)0x80000000);
}

Entrambe le costanti esadecimali precedenti sono di tipo uint.Both of the hexadecimal constants above are of type uint. Poiché le costanti non rientrano nell'intervallo di int, senza l'operatore unchecked, i cast a int produrrebbe errori in fase di compilazione.Because the constants are outside the int range, without the unchecked operator, the casts to int would produce compile-time errors.

Gli operatori e le istruzioni checked e unchecked consentono ai programmatori di controllare alcuni aspetti di alcuni calcoli numerici.The checked and unchecked operators and statements allow programmers to control certain aspects of some numeric calculations. Tuttavia, il comportamento di alcuni operatori numerici dipende dai tipi di dati degli operandi.However, the behavior of some numeric operators depends on their operands' data types. Se ad esempio si moltiplicano due decimali, viene sempre generata un'eccezione in caso di overflow anche all'interno di un costrutto unchecked in modo esplicito.For example, multiplying two decimals always results in an exception on overflow even within an explicitly unchecked construct. Analogamente, la moltiplicazione di due float non produce mai un'eccezione in un overflow anche all'interno di un costrutto checked in modo esplicito.Similarly, multiplying two floats never results in an exception on overflow even within an explicitly checked construct. Inoltre, gli altri operatori non sono mai interessati dalla modalità di controllo, sia che si tratti di un valore predefinito o esplicito.In addition, other operators are never affected by the mode of checking, whether default or explicit.

Espressioni con valore predefinitoDefault value expressions

Un'espressione con valore predefinito viene utilizzata per ottenere il valore predefinito (valori predefiniti) di un tipo.A default value expression is used to obtain the default value (Default values) of a type. Un'espressione con valore predefinito viene in genere utilizzata per i parametri di tipo, poiché potrebbe non essere noto se il parametro di tipo è un tipo di valore o un tipo di riferimento.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. Non esiste alcuna conversione dal valore letterale null a un parametro di tipo, a meno che il parametro di tipo non sia noto come tipo di riferimento.(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 ')'
    ;

Se il tipo in un default_value_expression restituisce in fase di esecuzione a un tipo riferimento, il risultato viene null convertito in quel tipo.If the type in a default_value_expression evaluates at run-time to a reference type, the result is null converted to that type. Se il tipo in un default_value_expression restituisce in fase di esecuzione a un tipo valore, il risultato è il valore predefinito del value_type(costruttori predefiniti).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).

Un default_value_expression è un'espressione costante (espressioni costanti) se il tipo è un tipo di riferimento o un parametro di tipo che è noto come tipo di riferimento (vincoli del parametro di tipo).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). Inoltre, un default_value_expression è un'espressione costante se il tipo è uno dei tipi di valore seguenti: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, boolo qualsiasi tipo di enumerazione.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.

Espressioni NameOfNameof expressions

Una nameof_expression viene utilizzata per ottenere il nome di un'entità di programma come stringa costante.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
    ;

In termini grammaticali, l'operando named_entity è sempre un'espressione.Grammatically speaking, the named_entity operand is always an expression. Poiché nameof non è una parola chiave riservata, un'espressione NameOf è sempre sintatticamente ambigua con una chiamata del nome semplice nameof.Because nameof is not a reserved keyword, a nameof expression is always syntactically ambiguous with an invocation of the simple name nameof. Per motivi di compatibilità, se una ricerca del nome (nomi semplici) del nome nameof ha esito positivo, l'espressione viene considerata come invocation_expression , indipendentemente dal fatto che la chiamata sia valida.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. In caso contrario, si tratta di un nameof_expression.Otherwise it is a nameof_expression.

Il significato del named_entity di un nameof_expression è il significato di esso come espressione; ovvero come simple_name, un base_access o un 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. Tuttavia, in cui la ricerca descritta in nomi semplici e accesso ai membri genera un errore perché un membro di istanza è stato trovato in un contesto statico, un nameof_expression genera un errore di questo tipo.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.

Si tratta di un errore in fase di compilazione per una named_entity che designa un gruppo di metodi per avere una type_argument_list.It is a compile-time error for a named_entity designating a method group to have a type_argument_list. Si tratta di un errore in fase di compilazione per un named_entity_target avere il tipo dynamic.It is a compile time error for a named_entity_target to have the type dynamic.

Un nameof_expression è un'espressione costante di tipo stringe non ha alcun effetto in fase di esecuzione.A nameof_expression is a constant expression of type string, and has no effect at runtime. In particolare, la relativa named_entity non viene valutata e viene ignorata ai fini dell'analisi dell'assegnazione definita (regole generali per le espressioni semplici).Specifically, its named_entity is not evaluated, and is ignored for the purposes of definite assignment analysis (General rules for simple expressions). Il valore è l'ultimo identificatore del named_entity prima della type_argument_listfinale facoltativa, trasformato nel modo seguente:Its value is the last identifier of the named_entity before the optional final type_argument_list, transformed in the following way:

  • Il prefisso "@", se usato, viene rimosso.The prefix "@", if used, is removed.
  • Ogni unicode_escape_sequence viene trasformato nel carattere Unicode corrispondente.Each unicode_escape_sequence is transformed into its corresponding Unicode character.
  • Eventuali formatting_characters vengono rimosse.Any formatting_characters are removed.

Si tratta delle stesse trasformazioni applicate negli identificatori quando si verifica l'uguaglianza tra gli identificatori.These are the same transformations applied in Identifiers when testing equality between identifiers.

TODO: esempiTODO: examples

Espressioni di metodo anonimeAnonymous method expressions

Un anonymous_method_expression è uno dei due modi per definire una funzione anonima.An anonymous_method_expression is one of two ways of defining an anonymous function. Questi sono descritti ulteriormente in espressioni di funzioni anonime.These are further described in Anonymous function expressions.

Operatori unariUnary operators

Gli operatori ?, +, -, !, ~, ++, --, cast e await sono denominati operatori unari.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
    ;

Se l'operando di un unary_expression dispone del tipo in fase di compilazione dynamic, è associato in modo dinamico (associazione dinamica).If the operand of a unary_expression has the compile-time type dynamic, it is dynamically bound (Dynamic binding). In questo caso il tipo in fase di compilazione del unary_expression viene dynamice la risoluzione descritta di seguito verrà eseguita in fase di esecuzione usando il tipo di runtime dell'operando.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.

Operatore condizionale nullNull-conditional operator

L'operatore condizionale null applica un elenco di operazioni al relativo operando solo se l'operando è diverso da null.The null-conditional operator applies a list of operations to its operand only if that operand is non-null. In caso contrario, il risultato dell'applicazione dell'operatore viene 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? ')'
    ;

L'elenco di operazioni può includere operazioni di accesso ai membri e di accesso agli elementi, che possono essere a loro volta condizionali null, nonché la chiamata.The list of operations can include member access and element access operations (which may themselves be null-conditional), as well as invocation.

Ad esempio, l'espressione a.b?[0]?.c() è un null_conditional_expression con un primary_expression a.b e null_conditional_operations ?[0] (accesso a elementi condizionali null), ?.c (accesso ai membri condizionali null) e () (chiamata).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).

Per un null_conditional_expression E con un primary_expression P, lasciare che E0 sia l'espressione ottenuta rimuovendo in modo testuale il ? principale da ognuno dei null_conditional_operations di E che ne hanno uno.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. Concettualmente, E0 è l'espressione che verrà valutata se nessuno dei controlli null rappresentati dall'?trova un null.Conceptually, E0 is the expression that will be evaluated if none of the null checks represented by the ?s do find a null.

Inoltre, E1 essere l'espressione ottenuta mediante la rimozione testuale della ? iniziale da solo il primo del null_conditional_operations in E.Also, let E1 be the expression obtained by textually removing the leading ? from just the first of the null_conditional_operations in E. Questo può causare un' espressione primaria (se è presente solo una ?) o a un'altra null_conditional_expression.This may lead to a primary-expression (if there was just one ?) or to another null_conditional_expression.

Se ad esempio E è l'espressione a.b?[0]?.c(), E0 è l'espressione a.b[0].c() e E1 è l'espressione 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().

Se E0 è classificato come Nothing, E viene classificato come Nothing.If E0 is classified as nothing, then E is classified as nothing. In caso contrario E è classificato come valore.Otherwise E is classified as a value.

E0 e E1 vengono utilizzati per determinare il significato di E:E0 and E1 are used to determine the meaning of E:

  • Se E si verifica come statement_expression il significato di E è uguale a quello dell'istruzioneIf E occurs as a statement_expression the meaning of E is the same as the statement

    if ((object)P != null) E1;
    

    ad eccezione del fatto che P viene valutato una sola volta.except that P is evaluated only once.

  • In caso contrario, se E0 viene classificato come Nothing, si verifica un errore in fase di compilazione.Otherwise, if E0 is classified as nothing a compile-time error occurs.

  • In caso contrario, consentire T0 essere il tipo di E0.Otherwise, let T0 be the type of E0.

    • Se T0 è un parametro di tipo che non è noto come tipo di riferimento o tipo di valore non nullable, si verifica un errore in fase di compilazione.If T0 is a type parameter that is not known to be a reference type or a non-nullable value type, a compile-time error occurs.

    • Se T0 è un tipo di valore non nullable, viene T0?il tipo di E e il significato di E è uguale aIf T0 is a non-nullable value type, then the type of E is T0?, and the meaning of E is the same as

      ((object)P == null) ? (T0?)null : E1
      

      con la differenza che P viene valutata una sola volta.except that P is evaluated only once.

    • In caso contrario, il tipo di E è T0 e il significato di E è uguale aOtherwise the type of E is T0, and the meaning of E is the same as

      ((object)P == null) ? null : E1
      

      con la differenza che P viene valutata una sola volta.except that P is evaluated only once.

Se E1 è a sua volta una null_conditional_expression, queste regole vengono applicate nuovamente, nidificando i test per null fino a quando non sono presenti ulteriori ?e l'espressione è stata ridotta fino al E0dell'espressione primaria.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.

Se, ad esempio, l'espressione a.b?[0]?.c() viene eseguita come espressione di istruzione, come nell'istruzione:For example, if the expression a.b?[0]?.c() occurs as a statement-expression, as in the statement:

a.b?[0]?.c();

il suo significato è equivalente a:its meaning is equivalent to:

if (a.b != null) a.b[0]?.c();

che è di nuovo equivalente a:which again is equivalent to:

if (a.b != null) if (a.b[0] != null) a.b[0].c();

Ad eccezione del fatto che a.b e a.b[0] vengono valutati una sola volta.Except that a.b and a.b[0] are evaluated only once.

Se si verifica in un contesto in cui viene utilizzato il relativo valore, come in:If it occurs in a context where its value is used, as in:

var x = a.b?[0]?.c();

e supponendo che il tipo della chiamata finale non sia un tipo di valore non nullable, il suo significato è equivalente a: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();

ad eccezione del fatto che a.b e a.b[0] vengono valutati una sola volta.except that a.b and a.b[0] are evaluated only once.

Espressioni condizionali null come inizializzatori di proiezioneNull-conditional expressions as projection initializers

Un'espressione condizionale null è consentita solo come member_declarator in una anonymous_object_creation_expression (espressioni dicreazione di oggetti anonimi) se termina con un accesso ai membri (facoltativamente 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. Grammaticalmente, questo requisito può essere espresso come segue: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?
    ;

Si tratta di un caso speciale della grammatica per null_conditional_expression sopra.This is a special case of the grammar for null_conditional_expression above. La produzione per member_declarator nelle espressioni di creazione di oggetti anonimi include quindi solo null_conditional_member_access.The production for member_declarator in Anonymous object creation expressions then includes only null_conditional_member_access.

Espressioni condizionali null come espressioni di istruzioneNull-conditional expressions as statement expressions

Un'espressione condizionale null è consentita solo come statement_expression (istruzioni Expression) se termina con una chiamata.A null-conditional expression is only allowed as a statement_expression (Expression statements) if it ends with an invocation. Grammaticalmente, questo requisito può essere espresso come segue:Grammatically, this requirement can be expressed as:

null_conditional_invocation_expression
    : primary_expression null_conditional_operations '(' argument_list? ')'
    ;

Si tratta di un caso speciale della grammatica per null_conditional_expression sopra.This is a special case of the grammar for null_conditional_expression above. La produzione per statement_expression nelle istruzioni Expression include quindi solo null_conditional_invocation_expression.The production for statement_expression in Expression statements then includes only null_conditional_invocation_expression.

Operatore più unarioUnary plus operator

Per un'operazione con il formato +x, viene applicata la risoluzione dell'overload dell'operatore unario (risoluzione dell'overload dell'operatore unario) per selezionare l'implementazione di un operatore specifico.For an operation of the form +x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. L'operando viene convertito nel tipo di parametro dell'operatore selezionato e il tipo del risultato è il tipo restituito dell'operatore.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. Gli operatori unario più predefiniti sono: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);

Per ognuno di questi operatori, il risultato è semplicemente il valore dell'operando.For each of these operators, the result is simply the value of the operand.

Operatore meno unarioUnary minus operator

Per un'operazione con il formato -x, viene applicata la risoluzione dell'overload dell'operatore unario (risoluzione dell'overload dell'operatore unario) per selezionare l'implementazione di un operatore specifico.For an operation of the form -x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. L'operando viene convertito nel tipo di parametro dell'operatore selezionato e il tipo del risultato è il tipo restituito dell'operatore.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. Gli operatori di negazione predefiniti sono:The predefined negation operators are:

  • Negazione integer:Integer negation:

    int operator -(int x);
    long operator -(long x);
    

    Il risultato viene calcolato sottraendo x da zero.The result is computed by subtracting x from zero. Se il valore di x è il più piccolo valore rappresentabile del tipo di operando (-2 ^ 31 per int o-2 ^ 63 per long), la negazione matematica di x non può essere rappresentata all'interno del tipo di operando.If the value of x is the smallest representable value of the operand type (-2^31 for int or -2^63 for long), then the mathematical negation of x is not representable within the operand type. Se questa situazione si verifica all'interno di un contesto di checked, viene generata un'System.OverflowException; Se si verifica all'interno di un contesto di unchecked, il risultato è il valore dell'operando e l'overflow non viene segnalato.If this occurs within a checked context, a System.OverflowException is thrown; if it occurs within an unchecked context, the result is the value of the operand and the overflow is not reported.

    Se l'operando dell'operatore di negazione è di tipo uint, viene convertito nel tipo longe il tipo del risultato è long.If the operand of the negation operator is of type uint, it is converted to type long, and the type of the result is long. Un'eccezione è la regola che consente la scrittura del valore int-2147483648 (-2 ^ 31) come valore letterale integer decimale (valoriletterali integer).An exception is the rule that permits the int value -2147483648 (-2^31) to be written as a decimal integer literal (Integer literals).

    Se l'operando dell'operatore di negazione è di tipo ulong, si verifica un errore in fase di compilazione.If the operand of the negation operator is of type ulong, a compile-time error occurs. Un'eccezione è la regola che consente la scrittura del valore long-9.223.372.036.854.775.808 (-2 ^ 63) come valore letterale integer decimale (valoriletterali integer).An exception is the rule that permits the long value -9223372036854775808 (-2^63) to be written as a decimal integer literal (Integer literals).

  • Negazione a virgola mobile:Floating-point negation:

    float operator -(float x);
    double operator -(double x);
    

    Il risultato è il valore di x con il segno invertito.The result is the value of x with its sign inverted. Se x è NaN, anche il risultato è NaN.If x is NaN, the result is also NaN.

  • Negazione decimale:Decimal negation:

    decimal operator -(decimal x);
    

    Il risultato viene calcolato sottraendo x da zero.The result is computed by subtracting x from zero. La negazione decimale equivale all'uso dell'operatore unario minus di tipo System.Decimal.Decimal negation is equivalent to using the unary minus operator of type System.Decimal.

Operatore di negazione logicaLogical negation operator

Per un'operazione con il formato !x, viene applicata la risoluzione dell'overload dell'operatore unario (risoluzione dell'overload dell'operatore unario) per selezionare l'implementazione di un operatore specifico.For an operation of the form !x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. L'operando viene convertito nel tipo di parametro dell'operatore selezionato e il tipo del risultato è il tipo restituito dell'operatore.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. Esiste un solo operatore di negazione logica predefinito:Only one predefined logical negation operator exists:

bool operator !(bool x);

Questo operatore calcola la negazione logica dell'operando: se l'operando è true, il risultato viene false.This operator computes the logical negation of the operand: If the operand is true, the result is false. Se l'operando è false, il risultato viene true.If the operand is false, the result is true.

Operatore di complemento bit per bitBitwise complement operator

Per un'operazione con il formato ~x, viene applicata la risoluzione dell'overload dell'operatore unario (risoluzione dell'overload dell'operatore unario) per selezionare l'implementazione di un operatore specifico.For an operation of the form ~x, unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. L'operando viene convertito nel tipo di parametro dell'operatore selezionato e il tipo del risultato è il tipo restituito dell'operatore.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. Gli operatori di complemento bit per bit predefiniti sono:The predefined bitwise complement operators are:

int operator ~(int x);
uint operator ~(uint x);
long operator ~(long x);
ulong operator ~(ulong x);

Per ognuno di questi operatori, il risultato dell'operazione è il complemento bit per bit di x.For each of these operators, the result of the operation is the bitwise complement of x.

Ogni tipo di enumerazione E fornisce in modo implicito l'operatore di complemento bit per bit seguente:Every enumeration type E implicitly provides the following bitwise complement operator:

E operator ~(E x);

Il risultato della valutazione di ~x, in cui x è un'espressione di un tipo di enumerazione E con un tipo sottostante U, è esattamente uguale alla valutazione (E)(~(U)x), ad eccezione del fatto che la conversione a E viene sempre eseguita come se si trovasse in un contesto unchecked (glioperatori checked e 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).

Operatori di incremento e decremento in forma prefissaPrefix increment and decrement operators

pre_increment_expression
    : '++' unary_expression
    ;

pre_decrement_expression
    : '--' unary_expression
    ;

L'operando di un'operazione di incremento o di decremento del prefisso deve essere un'espressione classificata come variabile, un accesso a una proprietà o un accesso all'indicizzatore.The operand of a prefix increment or decrement operation must be an expression classified as a variable, a property access, or an indexer access. Il risultato dell'operazione è un valore dello stesso tipo dell'operando.The result of the operation is a value of the same type as the operand.

Se l'operando di un'operazione di incremento o di decremento del prefisso è un accesso a una proprietà o a un indicizzatore, la proprietà o l'indicizzatore deve avere sia una funzione di accesso get che una 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. In caso contrario, si verificherà un errore in fase di binding.If this is not the case, a binding-time error occurs.

Viene applicata la risoluzione dell'overload dell'operatore unario (risoluzione dell'overload dell'operatore unario) per selezionare l'implementazione di un operatore specifico.Unary operator overload resolution (Unary operator overload resolution) is applied to select a specific operator implementation. Per i tipi seguenti sono disponibili gli operatori ++ e -- predefiniti: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimale qualsiasi tipo enum.Predefined ++ and -- operators exist for the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, and any enum type. Gli operatori ++ predefiniti restituiscono il valore prodotto aggiungendo 1 all'operando e gli operatori di -- predefiniti restituiscono il valore prodotto sottraendo 1 dall'operando.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 un contesto di checked, se il risultato di questa operazione di aggiunta o sottrazione non è compreso nell'intervallo del tipo di risultato e il tipo di risultato è un tipo integrale o un tipo enum, viene generata un'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.

L'elaborazione in fase di esecuzione di un'operazione di incremento o decremento del prefisso nel formato ++x o --x prevede i passaggi seguenti: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:If x is classified as a variable:
    • x is evaluated to produce the variable.x is evaluated to produce the variable.
    • L'operatore selezionato viene richiamato con il valore di x come argomento.The selected operator is invoked with the value of x as its argument.
    • Il valore restituito dall'operatore viene archiviato nella posizione specificata dalla valutazione del x.The value returned by the operator is stored in the location given by the evaluation of x.
    • Il valore restituito dall'operatore diventa il risultato dell'operazione.The value returned by the operator becomes the result of the operation.
  • Se x è classificato come accesso a una proprietà o a un indicizzatore:If x is classified as a property or indexer access:
    • L'espressione dell'istanza (se x non è static) e l'elenco di argomenti (se x è un accesso all'indicizzatore) associato a x vengono valutati e i risultati vengono utilizzati nelle chiamate successive get e set della funzione di accesso.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.
    • Viene richiamata la funzione di accesso get di x.The get accessor of x is invoked.
    • L'operatore selezionato viene richiamato con il valore restituito dalla funzione di accesso get come argomento.The selected operator is invoked with the value returned by the get accessor as its argument.
    • Viene richiamata la funzione di accesso set di x con il valore restituito dall'operatore come argomento value.The set accessor of x is invoked with the value returned by the operator as its value argument.
    • Il valore restituito dall'operatore diventa il risultato dell'operazione.The value returned by the operator becomes the result of the operation.

Gli operatori ++ e -- supportano anche la notazione suffissa (operatori di incremento e decremento suffisso).The ++ and -- operators also support postfix notation (Postfix increment and decrement operators). In genere, il risultato di x++ o x-- è il valore di x prima dell'operazione, mentre il risultato di ++x o --x è il valore di x dopo l'operazione.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 entrambi i casi, x stesso ha lo stesso valore dopo l'operazione.In either case, x itself has the same value after the operation.

È possibile richiamare un'implementazione di operator++ o operator-- utilizzando la notazione suffissa o prefisso.An operator++ or operator-- implementation can be invoked using either postfix or prefix notation. Non è possibile avere implementazioni di operatori separate per le due notazioni.It is not possible to have separate operator implementations for the two notations.

Espressioni castCast expressions

Una cast_expression viene utilizzata per convertire in modo esplicito un'espressione in un tipo specificato.A cast_expression is used to explicitly convert an expression to a given type.

cast_expression
    : '(' type ')' unary_expression
    ;

Cast_expression nel formato (T)E, in cui T è un tipo e E è un unary_expression, esegue una conversione esplicita (conversioni esplicite) del valore di E nel tipo 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. Se non esiste alcuna conversione esplicita dal E al T, si verifica un errore in fase di binding.If no explicit conversion exists from E to T, a binding-time error occurs. In caso contrario, il risultato è il valore prodotto dalla conversione esplicita.Otherwise, the result is the value produced by the explicit conversion. Il risultato viene sempre classificato come valore, anche se E denota una variabile.The result is always classified as a value, even if E denotes a variable.

La grammatica per un cast_expression conduce a determinate ambiguità sintattica.The grammar for a cast_expression leads to certain syntactic ambiguities. È possibile, ad esempio, interpretare l'espressione (x)-y come cast_expression (un cast di -y al tipo x) o come additive_expression combinato con un parenthesized_expression (che calcola il valore 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).

Per risolvere cast_expression ambiguità, esiste la regola seguente: una sequenza di uno o più tokens (spazi vuoti) racchiusa tra parentesi viene considerata l'inizio di una cast_expression solo se si verifica almeno una delle condizioni seguenti:To resolve cast_expression ambiguities, the following rule exists: A sequence of one or more tokens (White space) enclosed in parentheses is considered the start of a cast_expression only if at least one of the following are true:

  • La sequenza di token è la grammatica corretta per un tipo, ma non per un' espressione.The sequence of tokens is correct grammar for a type, but not for an expression.
  • La sequenza di token è la grammatica corretta per un tipoe il token che segue immediatamente le parentesi di chiusura è il token "~", il token "!", il token "(", un identificatore (sequenze di escape di caratteri Unicode), un valore letterale (valori letterali) o qualsiasi parola chiave (parolechiave) tranne as e 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) except as and is.

Il termine "grammatica corretta" riportata in precedenza significa solo che la sequenza di token deve essere conforme alla particolare produzione grammaticale.The term "correct grammar" above means only that the sequence of tokens must conform to the particular grammatical production. In particolare, non considera il significato effettivo di tutti gli identificatori costitutivi.It specifically does not consider the actual meaning of any constituent identifiers. Se ad esempio x e y sono identificatori, x.y è la grammatica corretta per un tipo, anche se x.y non denota effettivamente un tipo.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.

Dalla regola di risoluzione dell'ambiguità segue che, se x e y sono identificatori, (x)y, (x)(y)e (x)(-y) sono cast_expressions, ma (x)-y non lo è, anche se x identifica un tipo.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. Tuttavia, se x è una parola chiave che identifica un tipo predefinito, ad esempio int, tutti e quattro i form sono cast_expressions (perché tale parola chiave non può essere un'espressione da sola).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).

Espressioni awaitAwait expressions

L'operatore await viene usato per sospendere la valutazione della funzione asincrona di inclusione fino al completamento dell'operazione asincrona rappresentata dall'operando.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
    ;

Una await_expression è consentita solo nel corpo di una funzione asincrona (iteratori).An await_expression is only allowed in the body of an async function (Iterators). All'interno della funzione asincrona di inclusione più vicina, un await_expression potrebbe non essere presente in queste posizioni:Within the nearest enclosing async function, an await_expression may not occur in these places:

  • All'interno di una funzione anonima (non asincrona) nidificataInside a nested (non-async) anonymous function
  • All'interno del blocco di un lock_statementInside the block of a lock_statement
  • In un contesto non sicuroIn an unsafe context

Si noti che non è possibile eseguire un await_expression nella maggior parte dei punti all'interno di un query_expression, perché questi vengono sintatticamente trasformati in modo da usare espressioni lambda non asincrone.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.

All'interno di una funzione asincrona, non è possibile usare await come identificatore.Inside of an async function, await cannot be used as an identifier. Non esiste pertanto alcuna ambiguità sintattica tra le espressioni await e le varie espressioni che coinvolgono gli identificatori.There is therefore no syntactic ambiguity between await-expressions and various expressions involving identifiers. All'esterno delle funzioni asincrone, await funge da identificatore normale.Outside of async functions, await acts as a normal identifier.

L'operando di un await_expression è denominato attività.The operand of an await_expression is called the task. Rappresenta un'operazione asincrona che può essere o meno completata al momento della valutazione del await_expression .It represents an asynchronous operation that may or may not be complete at the time the await_expression is evaluated. Lo scopo dell'operatore await è sospendere l'esecuzione della funzione asincrona di inclusione fino al completamento dell'attività attesa e quindi ottenere il risultato.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.

Espressioni awaitableAwaitable expressions

È necessario che l'attività di un'espressione await sia awaitable.The task of an await expression is required to be awaitable. Un'espressione t è awaitable se uno degli elementi seguenti include:An expression t is awaitable if one of the following holds:

  • t è di tipo tempo di compilazione dynamict is of compile time type dynamic
  • t dispone di un'istanza accessibile o di un metodo di estensione denominato GetAwaiter senza parametri e nessun parametro di tipo e un tipo restituito A per il quale sono presenti tutti gli elementi seguenti: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:
    • A implementa l'interfaccia System.Runtime.CompilerServices.INotifyCompletion (in seguito nota come INotifyCompletion per brevità)A implements the interface System.Runtime.CompilerServices.INotifyCompletion (hereafter known as INotifyCompletion for brevity)
    • A dispone di una proprietà di istanza accessibile e leggibile IsCompleted di tipo boolA has an accessible, readable instance property IsCompleted of type bool
    • A dispone di un metodo di istanza accessibile GetResult senza parametri e nessun parametro di tipoA has an accessible instance method GetResult with no parameters and no type parameters

Lo scopo del GetAwaiter metodo è ottenere un awaiter per l'attività.The purpose of the GetAwaiter method is to obtain an awaiter for the task. Il tipo A viene chiamato tipo awaiter per l'espressione await.The type A is called the awaiter type for the await expression.

Lo scopo della proprietà IsCompleted è determinare se l'attività è già stata completata.The purpose of the IsCompleted property is to determine if the task is already complete. In tal caso, non è necessario sospendere la valutazione.If so, there is no need to suspend evaluation.

Lo scopo del INotifyCompletion.OnCompleted metodo consiste nell'iscrivere una "continuazione" all'attività; ovvero un delegato (di tipo System.Action) che verrà richiamato una volta completata l'attività.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.

Lo scopo del GetResult metodo è ottenere il risultato dell'attività dopo che è stata completata.The purpose of the GetResult method is to obtain the outcome of the task once it is complete. Questo risultato può essere completato correttamente, possibilmente con un valore di risultato, oppure può essere un'eccezione generata dal metodo 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.

Classificazione delle espressioni awaitClassification of await expressions

Il await t di espressione è classificato allo stesso modo dell'espressione (t).GetAwaiter().GetResult().The expression await t is classified the same way as the expression (t).GetAwaiter().GetResult(). Pertanto, se il tipo restituito di GetResult è void, il await_expression viene classificato come Nothing.Thus, if the return type of GetResult is void, the await_expression is classified as nothing. Se dispone di un tipo restituito non void T, il await_expression viene classificato come valore di tipo T.If it has a non-void return type T, the await_expression is classified as a value of type T.

Valutazione del runtime delle espressioni awaitRuntime evaluation of await expressions

In fase di esecuzione, l'espressione await t viene valutata nel modo seguente:At runtime, the expression await t is evaluated as follows:

  • Un awaiter a viene ottenuto valutando l'espressione (t).GetAwaiter().An awaiter a is obtained by evaluating the expression (t).GetAwaiter().
  • Una bool b viene ottenuta valutando il (a).IsCompleteddell'espressione.A bool b is obtained by evaluating the expression (a).IsCompleted.
  • Se b è false, la valutazione dipende dal fatto che a implementi l'interfaccia System.Runtime.CompilerServices.ICriticalNotifyCompletion (in seguito nota come ICriticalNotifyCompletion per brevità).If b is false then evaluation depends on whether a implements the interface System.Runtime.CompilerServices.ICriticalNotifyCompletion (hereafter known as ICriticalNotifyCompletion for brevity). Questa verifica viene eseguita in fase di binding. ad esempio, in fase di esecuzione se a dispone del tipo di tempo di compilazione dynamice in fase di compilazione in caso contrario.This check is done at binding time; i.e. at runtime if a has the compile time type dynamic, and at compile time otherwise. Let r indicare il delegato di ripresa (iteratori):Let r denote the resumption delegate (Iterators):
    • Se a non implementa ICriticalNotifyCompletion, l'espressione (a as (INotifyCompletion)).OnCompleted(r) viene valutata.If a does not implement ICriticalNotifyCompletion, then the expression (a as (INotifyCompletion)).OnCompleted(r) is evaluated.
    • Se a implementa ICriticalNotifyCompletion, l'espressione (a as (ICriticalNotifyCompletion)).UnsafeOnCompleted(r) viene valutata.If a does implement ICriticalNotifyCompletion, then the expression (a as (ICriticalNotifyCompletion)).UnsafeOnCompleted(r) is evaluated.
    • La valutazione viene quindi sospesa e il controllo viene restituito al chiamante corrente della funzione asincrona.Evaluation is then suspended, and control is returned to the current caller of the async function.
  • Immediatamente dopo (se b è stato true) o dopo una chiamata successiva del delegato di ripresa (se b è stato false), viene valutata l'espressione (a).GetResult().Either immediately after (if b was true), or upon later invocation of the resumption delegate (if b was false), the expression (a).GetResult() is evaluated. Se restituisce un valore, tale valore è il risultato della await_expression.If it returns a value, that value is the result of the await_expression. In caso contrario, il risultato è Nothing.Otherwise the result is nothing.

L'implementazione di un awaiter dei metodi di interfaccia INotifyCompletion.OnCompleted e ICriticalNotifyCompletion.UnsafeOnCompleted deve fare in modo che il delegato r venga richiamato al massimo una volta.An awaiter's implementation of the interface methods INotifyCompletion.OnCompleted and ICriticalNotifyCompletion.UnsafeOnCompleted should cause the delegate r to be invoked at most once. In caso contrario, il comportamento della funzione asincrona di inclusione non è definito.Otherwise, the behavior of the enclosing async function is undefined.

Operatori aritmeticiArithmetic operators

Gli operatori *, /, %, +e - sono detti operatori aritmetici.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
    ;

Se un operando di un operatore aritmetico ha il tipo dynamicin fase di compilazione, l'espressione viene associata dinamicamente (associazione dinamica).If an operand of an arithmetic operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). In questo caso il tipo in fase di compilazione dell'espressione viene dynamice la risoluzione descritta di seguito verrà eseguita in fase di esecuzione usando il tipo di runtime degli operandi che hanno il tipo in fase di compilazione 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.

Operatore di moltiplicazioneMultiplication operator

Per un'operazione con il formato x * y, viene applicata la risoluzione dell'overload degli operatori binari (risoluzione dell'overload degli operatori binari) per selezionare un'implementazione specifica dell'operatore.For an operation of the form x * y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Gli operandi vengono convertiti nei tipi di parametro dell'operatore selezionato e il tipo del risultato è il tipo restituito dell'operatore.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.

Gli operatori di moltiplicazione predefiniti sono elencati di seguito.The predefined multiplication operators are listed below. Tutti gli operatori calcolano il prodotto di x e y.The operators all compute the product of x and y.

  • Moltiplicazione Integer: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);
    

    In un contesto di checked, se il prodotto non è compreso nell'intervallo del tipo di risultato, viene generata un'System.OverflowException.In a checked context, if the product is outside the range of the result type, a System.OverflowException is thrown. In un contesto di unchecked, gli overflow non vengono segnalati e tutti i bit di ordine superiore significativi che non rientrano nell'intervallo del tipo di risultato vengono eliminati.In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.

  • Moltiplicazione a virgola mobile:Floating-point multiplication:

    float operator *(float x, float y);
    double operator *(double x, double y);
    

    Il prodotto viene calcolato in base alle regole dell'aritmetica IEEE 754.The product is computed according to the rules of IEEE 754 arithmetic. Nella tabella seguente sono elencati i risultati di tutte le possibili combinazioni di valori finiti diversi da zero, zeri, infiniti e NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. Nella tabella x e y sono valori finiti positivi.In the table, x and y are positive finite values. z è il risultato della x * y.z is the result of x * y. Se il risultato è troppo grande per il tipo di destinazione, z è infinito.If the result is too large for the destination type, z is infinity. Se il risultato è troppo piccolo per il tipo di destinazione, z è zero.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
  • Moltiplicazione decimale:Decimal multiplication:

    decimal operator *(decimal x, decimal y);
    

    Se il valore risultante è troppo grande per essere rappresentato nel formato decimal, viene generata un'System.OverflowException.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. Se il valore del risultato è troppo piccolo per essere rappresentato nel formato decimal, il risultato è zero.If the result value is too small to represent in the decimal format, the result is zero. La scala del risultato, prima di qualsiasi arrotondamento, è la somma delle scale dei due operandi.The scale of the result, before any rounding, is the sum of the scales of the two operands.

    La moltiplicazione decimale è equivalente all'utilizzo dell'operatore di moltiplicazione di tipo System.Decimal.Decimal multiplication is equivalent to using the multiplication operator of type System.Decimal.

Operatore di divisioneDivision operator

Per un'operazione con il formato x / y, viene applicata la risoluzione dell'overload degli operatori binari (risoluzione dell'overload degli operatori binari) per selezionare un'implementazione specifica dell'operatore.For an operation of the form x / y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Gli operandi vengono convertiti nei tipi di parametro dell'operatore selezionato e il tipo del risultato è il tipo restituito dell'operatore.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.

Gli operatori di divisione predefiniti sono elencati di seguito.The predefined division operators are listed below. Tutti gli operatori calcolano il quoziente di x e y.The operators all compute the quotient of x and y.

  • Divisione Integer: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);
    

    Se il valore dell'operando destro è zero, viene generata un'System.DivideByZeroException.If the value of the right operand is zero, a System.DivideByZeroException is thrown.

    La divisione arrotonda il risultato verso lo zero.The division rounds the result towards zero. Pertanto, il valore assoluto del risultato è il numero intero massimo possibile minore o uguale al valore assoluto del quoziente dei due operandi.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. Il risultato è zero o positivo quando i due operandi hanno lo stesso segno e zero o negativo quando i due operandi hanno segni opposti.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.

    Se l'operando sinistro è il più piccolo int rappresentabile o long valore e l'operando destro è -1, si verifica un overflow.If the left operand is the smallest representable int or long value and the right operand is -1, an overflow occurs. In un contesto di checked, in questo modo viene generata una System.ArithmeticException (o una sottoclasse).In a checked context, this causes a System.ArithmeticException (or a subclass thereof) to be thrown. In un contesto di unchecked, viene definito in fase di implementazione, a seconda che venga generata una System.ArithmeticException (o una sottoclasse) o che l'overflow non venga segnalato con il valore risultante che corrisponde a quello dell'operando sinistro.In an unchecked context, it is implementation-defined as to whether a System.ArithmeticException (or a subclass thereof) is thrown or the overflow goes unreported with the resulting value being that of the left operand.

  • Divisione a virgola mobile:Floating-point division:

    float operator /(float x, float y);
    double operator /(double x, double y);
    

    Il quoziente viene calcolato in base alle regole dell'aritmetica IEEE 754.The quotient is computed according to the rules of IEEE 754 arithmetic. Nella tabella seguente sono elencati i risultati di tutte le possibili combinazioni di valori finiti diversi da zero, zeri, infiniti e NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. Nella tabella x e y sono valori finiti positivi.In the table, x and y are positive finite values. z è il risultato della x / y.z is the result of x / y. Se il risultato è troppo grande per il tipo di destinazione, z è infinito.If the result is too large for the destination type, z is infinity. Se il risultato è troppo piccolo per il tipo di destinazione, z è zero.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
  • Divisione decimale:Decimal division:

    decimal operator /(decimal x, decimal y);
    

    Se il valore dell'operando destro è zero, viene generata un'System.DivideByZeroException.If the value of the right operand is zero, a System.DivideByZeroException is thrown. Se il valore risultante è troppo grande per essere rappresentato nel formato decimal, viene generata un'System.OverflowException.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. Se il valore del risultato è troppo piccolo per essere rappresentato nel formato decimal, il risultato è zero.If the result value is too small to represent in the decimal format, the result is zero. La scala del risultato è la scala più piccola che conserverà un risultato uguale al valore decimale rappresentabile più vicino al vero risultato matematico.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.

    La divisione decimale equivale all'uso dell'operatore di divisione di tipo System.Decimal.Decimal division is equivalent to using the division operator of type System.Decimal.

Operatore di restoRemainder operator

Per un'operazione con il formato x % y, viene applicata la risoluzione dell'overload degli operatori binari (risoluzione dell'overload degli operatori binari) per selezionare un'implementazione specifica dell'operatore.For an operation of the form x % y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Gli operandi vengono convertiti nei tipi di parametro dell'operatore selezionato e il tipo del risultato è il tipo restituito dell'operatore.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.

Gli operatori di resto predefiniti sono elencati di seguito.The predefined remainder operators are listed below. Tutti gli operatori calcolano il resto della divisione tra x e y.The operators all compute the remainder of the division between x and y.

  • Resto integer: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);
    

    Il risultato di x % y è il valore prodotto da x - (x / y) * y.The result of x % y is the value produced by x - (x / y) * y. Se y è zero, viene generata un'System.DivideByZeroException.If y is zero, a System.DivideByZeroException is thrown.

    Se l'operando sinistro è il più piccolo int o long valore e l'operando destro è -1, viene generata un'System.OverflowException.If the left operand is the smallest int or long value and the right operand is -1, a System.OverflowException is thrown. In nessun caso x % y generare un'eccezione in cui x / y non genererebbe un'eccezione.In no case does x % y throw an exception where x / y would not throw an exception.

  • Resto a virgola mobile:Floating-point remainder:

    float operator %(float x, float y);
    double operator %(double x, double y);
    

    Nella tabella seguente sono elencati i risultati di tutte le possibili combinazioni di valori finiti diversi da zero, zeri, infiniti e NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. Nella tabella x e y sono valori finiti positivi.In the table, x and y are positive finite values. z è il risultato della x % y e viene calcolato come x - n * y, dove n è il numero intero massimo possibile minore o uguale a x / y.z is the result of x % y and is computed as x - n * y, where n is the largest possible integer that is less than or equal to x / y. Questo metodo di calcolo del resto è analogo a quello usato per gli operandi Integer, ma è diverso dalla definizione IEEE 754 (in cui n è il numero intero più vicino alla x / y).This method of computing the remainder is analogous to that used for integer operands, but differs from the IEEE 754 definition (in which n is the integer closest to x / 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
  • Resto decimale:Decimal remainder:

    decimal operator %(decimal x, decimal y);
    

    Se il valore dell'operando destro è zero, viene generata un'System.DivideByZeroException.If the value of the right operand is zero, a System.DivideByZeroException is thrown. La scala del risultato, prima di qualsiasi arrotondamento, è la maggiore delle scale dei due operandi e il segno del risultato, se diverso da zero, è uguale a quello di 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 of x.

    Il resto decimale equivale all'uso dell'operatore resto di tipo System.Decimal.Decimal remainder is equivalent to using the remainder operator of type System.Decimal.

Operatore di addizioneAddition operator

Per un'operazione con il formato x + y, viene applicata la risoluzione dell'overload degli operatori binari (risoluzione dell'overload degli operatori binari) per selezionare un'implementazione specifica dell'operatore.For an operation of the form x + y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Gli operandi vengono convertiti nei tipi di parametro dell'operatore selezionato e il tipo del risultato è il tipo restituito dell'operatore.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.

Gli operatori di addizione predefiniti sono elencati di seguito.The predefined addition operators are listed below. Per i tipi numerici e di enumerazione, gli operatori di addizione predefiniti calcolano la somma dei due operandi.For numeric and enumeration types, the predefined addition operators compute the sum of the two operands. Quando uno o entrambi gli operandi sono di tipo stringa, gli operatori di addizione predefiniti concatenano la rappresentazione di stringa degli operandi.When one or both operands are of type string, the predefined addition operators concatenate the string representation of the operands.

  • Aggiunta Integer: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);
    

    In un contesto di checked, se la somma non è compresa nell'intervallo del tipo di risultato, viene generata un'System.OverflowException.In a checked context, if the sum is outside the range of the result type, a System.OverflowException is thrown. In un contesto di unchecked, gli overflow non vengono segnalati e tutti i bit di ordine superiore significativi che non rientrano nell'intervallo del tipo di risultato vengono eliminati.In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.

  • Aggiunta a virgola mobile:Floating-point addition:

    float operator +(float x, float y);
    double operator +(double x, double y);
    

    La somma viene calcolata in base alle regole dell'aritmetica IEEE 754.The sum is computed according to the rules of IEEE 754 arithmetic. Nella tabella seguente sono elencati i risultati di tutte le possibili combinazioni di valori finiti diversi da zero, zeri, infiniti e NaN.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN's. Nella tabella x e y sono valori finiti diversi da zero e z è il risultato della x + y.In the table, x and y are nonzero finite values, and z is the result of x + y. Se x e y hanno la stessa grandezza ma segni opposti, z è zero positivo.If x and y have the same magnitude but opposite signs, z is positive zero. Se x + y è troppo grande per essere rappresentato nel tipo di destinazione, z è un infinito con lo stesso segno di x + y.If x + y is too large to represent in the destination type, z is an infinity with the same sign as x + y.

    sy +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    xx lz xx xx +inf+inf -inf-inf NaNNaN
    +0+0 sy +0+0 +0+0 +inf+inf -inf-inf NaNNaN
    -0-0 sy +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
  • Addizione decimale:Decimal addition:

    decimal operator +(decimal x, decimal y);
    

    Se il valore risultante è troppo grande per essere rappresentato nel formato decimal, viene generata un'System.OverflowException.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. La scala del risultato, prima di qualsiasi arrotondamento, è la maggiore delle scale dei due operandi.The scale of the result, before any rounding, is the larger of the scales of the two operands.

    L'addizione decimale equivale all'uso dell'operatore di addizione di tipo System.Decimal.Decimal addition is equivalent to using the addition operator of type System.Decimal.

  • Aggiunta dell'enumerazione.Enumeration addition. Ogni tipo di enumerazione fornisce in modo implicito gli operatori predefiniti seguenti, dove E è il tipo enum e U è il tipo sottostante di E:Every enumeration type implicitly provides the following predefined operators, where E is the enum type, and U is the underlying type of E:

    E operator +(E x, U y);
    E operator +(U x, E y);
    

    In fase di esecuzione questi operatori vengono valutati esattamente come (E)((U)x + (U)y).At run-time these operators are evaluated exactly as (E)((U)x + (U)y).

  • Concatenazione di stringhe:String concatenation:

    string operator +(string x, string y);
    string operator +(string x, object y);
    string operator +(object x, string y);
    

    Questi overload dell'operatore + binario eseguono la concatenazione di stringhe.These overloads of the binary + operator perform string concatenation. Se un operando di concatenazione di stringhe è null, viene sostituita una stringa vuota.If an operand of string concatenation is null, an empty string is substituted. In caso contrario, qualsiasi argomento non di tipo stringa viene convertito nella relativa rappresentazione di stringa richiamando il metodo ToString virtuale ereditato dal tipo object.Otherwise, any non-string argument is converted to its string representation by invoking the virtual ToString method inherited from type object. Se ToString restituisce null, viene sostituita una stringa vuota.If ToString returns null, 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
        }
    }
    

    Il risultato dell'operatore di concatenazione delle stringhe è una stringa costituita dai caratteri dell'operando sinistro, seguiti dai caratteri dell'operando di destra. L'operatore di concatenazione delle stringhe non restituisce mai un valore null. Se non è disponibile memoria sufficiente per allocare la stringa risultante, è possibile che venga generata un'System.OutOfMemoryException.A System.OutOfMemoryException may be thrown if there is not enough memory available to allocate the resulting string.

  • Combinazione di delegati.Delegate combination. Ogni tipo delegato fornisce in modo implicito l'operatore predefinito seguente, dove D è il tipo delegato:Every delegate type implicitly provides the following predefined operator, where D is the delegate type:

    D operator +(D x, D y);
    

    L'operatore + binario esegue una combinazione di delegati quando entrambi gli operandi sono di tipo delegato D.The binary + operator performs delegate combination when both operands are of some delegate type D. Se gli operandi hanno tipi delegati diversi, si verifica un errore in fase di binding. Se il primo operando è null, il risultato dell'operazione è il valore del secondo operando (anche se anche null).(If the operands have different delegate types, a binding-time error occurs.) If the first operand is null, the result of the operation is the value of the second operand (even if that is also null). In caso contrario, se il secondo operando è null, il risultato dell'operazione è il valore del primo operando.Otherwise, if the second operand is null, then the result of the operation is the value of the first operand. In caso contrario, il risultato dell'operazione è una nuova istanza di delegato che, quando richiamata, richiama il primo operando e quindi richiama il secondo operando.Otherwise, the result of the operation is a new delegate instance that, when invoked, invokes the first operand and then invokes the second operand. Per esempi di combinazione di delegati, vedere operatore di sottrazione e chiamata al delegato.For examples of delegate combination, see Subtraction operator and Delegate invocation. Poiché System.Delegate non è un tipo delegato, operator + non è definito.Since System.Delegate is not a delegate type, operator + is not defined for it.

Operatore di sottrazioneSubtraction operator

Per un'operazione con il formato x - y, viene applicata la risoluzione dell'overload degli operatori binari (risoluzione dell'overload degli operatori binari) per selezionare un'implementazione specifica dell'operatore.For an operation of the form x - y, binary operator overload resolution (Binary operator overload resolution) is applied to select a specific operator implementation. Gli operandi vengono convertiti nei tipi di parametro dell'operatore selezionato e il tipo del risultato è il tipo restituito dell'operatore.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.

Gli operatori di sottrazione predefiniti sono elencati di seguito.The predefined subtraction operators are listed below. Gli operatori sottraggono tutti y da x.The operators all subtract y from x.

  • Sottrazione integer: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);
    

    In un contesto di checked, se la differenza non è compresa nell'intervallo del tipo di risultato, viene generata un'System.OverflowException.In a checked context, if the difference is outside the range of the result type, a System.OverflowException is thrown. In un contesto di unchecked, gli overflow non vengono segnalati e tutti i bit di ordine superiore significativi che non rientrano nell'intervallo del tipo di risultato vengono eliminati.In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.

  • Sottrazione a virgola mobile:Floating-point subtraction:

    float operator -(float x, float y);
    double operator -(double x, double y);
    

    La differenza viene calcolata in base alle regole dell'aritmetica IEEE 754.The difference is computed according to the rules of IEEE 754 arithmetic. Nella tabella seguente sono elencati i risultati di tutte le possibili combinazioni di valori finiti diversi da zero, zeri, infiniti e NaNs.The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaNs. Nella tabella x e y sono valori finiti diversi da zero e z è il risultato della x - y.In the table, x and y are nonzero finite values, and z is the result of x - y. Se x e y sono uguali, z è zero positivo.If x and y are equal, z is positive zero. Se x - y è troppo grande per essere rappresentato nel tipo di destinazione, z è un infinito con lo stesso segno di x - y.If x - y is too large to represent in the destination type, z is an infinity with the same sign as x - y.

    sy +0+0 -0-0 +inf+inf -inf-inf NaNNaN
    xx lz 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
  • Sottrazione decimale:Decimal subtraction:

    decimal operator -(decimal x, decimal y);
    

    Se il valore risultante è troppo grande per essere rappresentato nel formato decimal, viene generata un'System.OverflowException.If the resulting value is too large to represent in the decimal format, a System.OverflowException is thrown. La scala del risultato, prima di qualsiasi arrotondamento, è la maggiore delle scale dei due operandi.The scale of the result, before any rounding, is the larger of the scales of the two operands.

    La sottrazione decimale equivale all'uso dell'operatore di sottrazione di tipo System.Decimal.Decimal subtraction is equivalent to using the subtraction operator of type System.Decimal.

  • Sottrazione di enumerazione.Enumeration subtraction. Ogni tipo di enumerazione fornisce in modo implicito l'operatore predefinito seguente, dove E è il tipo enum e U è il tipo sottostante di E:Every enumeration type implicitly provides the following predefined operator, where E is the enum type, and U is the underlying type of E:

    U operator -(E x, E y);
    

    Questo operatore viene valutato esattamente come (U)((U)x - (U)y).This operator is evaluated exactly as (U)((U)x - (U)y). In altre parole, l'operatore calcola la differenza tra i valori ordinali di x e ye il tipo del risultato è il tipo sottostante dell'enumerazione.In other words, the operator computes the difference between the ordinal values of x and y, and the type of the result is the underlying type of the enumeration.

    E operator -(E x, U y);
    

    Questo operatore viene valutato esattamente come (E)((U)x - y).This operator is evaluated exactly as (E)((U)x - y). In altre parole, l'operatore sottrae un valore dal tipo sottostante dell'enumerazione, restituendo un valore dell'enumerazione.In other words, the operator subtracts a value from the underlying type of the enumeration, yielding a value of the enumeration.

  • Rimozione del delegato.Delegate removal. Ogni tipo delegato fornisce in modo implicito l'operatore predefinito seguente, dove D è il tipo delegato:Every delegate type implicitly provides the following predefined operator, where D is the delegate type:

    D operator -(D x, D y);
    

    L'operatore - binario esegue la rimozione dei delegati quando entrambi gli operandi sono di tipo delegato D.The binary - operator performs delegate removal when both operands are of some delegate type D. Se gli operandi hanno tipi delegati diversi, si verifica un errore in fase di binding.If the operands have different delegate types, a binding-time error occurs. Se il primo operando è null, il risultato dell'operazione è null.If the first operand is null, the result of the operation is null. In caso contrario, se il secondo operando è null, il risultato dell'operazione è il valore del primo operando.Otherwise, if the second operand is null, then the result of the operation is the value of the first operand. In caso contrario, entrambi gli operandi rappresentano elenchi chiamate (dichiarazioni delegate) con una o più voci e il risultato è un nuovo elenco chiamate costituito dall'elenco del primo operando con le voci del secondo operando rimosse, purché l'elenco del secondo operando sia un sottoelenco contiguo appropriato della prima.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. Per determinare l'uguaglianza di sottoelenchi, le voci corrispondenti vengono confrontate come per l'operatore di uguaglianza dei delegati (operatori di uguaglianza dei delegati). In caso contrario, il risultato è il valore dell'operando sinistro.(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. Nessuno degli operandi è stato modificato nel processo.Neither of the operands' lists is changed in the process. Se l'elenco del secondo operando corrisponde a più sottoelenchi di voci contigue nell'elenco del primo operando, viene rimosso il sottoelenco corrispondente più a destra delle voci contigue.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. Se la rimozione restituisce un elenco vuoto, il risultato è null.If removal results in an empty list, the result is null. Ad esempio: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
        }
    }
    

Operatori shiftShift operators

Gli operatori << e >> vengono utilizzati per eseguire operazioni di spostamento di bit.The << and >> operators are used to perform bit shifting operations.

shift_expression
    : additive_expression
    | shift_expression '<<' additive_expression
    | shift_expression right_shift additive_expression
    ;

Se un operando di un shift_expression dispone del tipo in fase di compilazione dynamic, l'espressione è associata dinamicamente (associazione dinamica).If an operand of a shift_expression has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). In questo caso il tipo in fase di compilazione dell'espressione viene dynamice la risoluzione descritta di seguito verrà eseguita in fase di esecuzione usando il tipo di runtime degli operandi che hanno il tipo in fase di compilazione 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.

Per un'operazione con il formato x << count o x >> count, viene applicata la risoluzione dell'overload degli operatori binari (risoluzione dell'overload degli operatori binari) per selezionare un'implementazione specifica dell'operatore.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. Gli operandi vengono convertiti nei tipi di parametro dell'operatore selezionato e il tipo del risultato è il tipo restituito dell'operatore.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.

Quando si dichiara un operatore Shift di overload, il tipo del primo operando deve essere sempre la classe o lo struct che contiene la dichiarazione dell'operatore e il tipo del secondo operando deve sempre essere 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.

Gli operatori shift predefiniti sono elencati di seguito.The predefined shift operators are listed below.

  • Spostamento a sinistra: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);
    

    L'operatore << sposta x sinistra di un numero di bit calcolato come descritto di seguito.The << operator shifts x left by a number of bits computed as described below.

    I bit più significativi non compresi nell'intervallo del tipo di risultato di x vengono eliminati, i bit rimanenti vengono spostati a sinistra e le posizioni di bit vuote di ordine inferiore vengono impostate su zero.The high-order bits outside the range of the result type of x are discarded, the remaining bits are shifted left, and the low-order empty bit positions are set to zero.

  • Spostamento a destra: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);
    

    L'operatore >> sposta x destra di un numero di bit calcolato come descritto di seguito.The >> operator shifts x right by a number of bits computed as described below.

    Se x è di tipo int o long, i bit meno significativi di x vengono eliminati, i bit rimanenti vengono spostati a destra e le posizioni di bit vuote di ordine superiore vengono impostate su zero se x è non negativo e viene impostato su uno se x è negativo.When x is of type int or long, the low-order bits of x are discarded, the remaining bits are shifted right, and the high-order empty bit positions are set to zero if x is non-negative and set to one if x is negative.

    Se x è di tipo uint o ulong, i bit meno significativi del x vengono eliminati, i bit rimanenti vengono spostati a destra e le posizioni di bit vuote di ordine superiore sono impostate su zero.When x is of type uint or ulong, the low-order bits of x are discarded, the remaining bits are shifted right, and the high-order empty bit positions are set to zero.

Per gli operatori predefiniti, il numero di bit da spostare viene calcolato nel modo seguente:For the predefined operators, the number of bits to shift is computed as follows:

  • Quando il tipo di x è int o uint, il conteggio dello spostamento viene assegnato dai cinque bit meno significativi di count.When the type of x is int or uint, the shift count is given by the low-order five bits of count. In altre parole, il conteggio dello spostamento viene calcolato da count & 0x1F.In other words, the shift count is computed from count & 0x1F.
  • Quando il tipo di x è long o ulong, il conteggio dello spostamento viene assegnato dai sei bit meno significativi di count.When the type of x is long or ulong, the shift count is given by the low-order six bits of count. In altre parole, il conteggio dello spostamento viene calcolato da count & 0x3F.In other words, the shift count is computed from count & 0x3F.

Se il numero di spostamenti risultante è pari a zero, gli operatori shift restituiscono semplicemente il valore di x.If the resulting shift count is zero, the shift operators simply return the value of x.

Le operazioni di spostamento non causano mai overflow e producono gli stessi risultati in contesti checked e unchecked.Shift operations never cause overflows and produce the same results in checked and unchecked contexts.

Quando l'operando sinistro dell'operatore >> è di un tipo integrale con segno, l'operatore esegue un diritto di spostamento aritmetico in cui il valore del bit più significativo (il bit di segno) dell'operando viene propagato alle posizioni di bit vuote di ordine superiore.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. Quando l'operando sinistro dell'operatore >> è di un tipo integrale senza segno, l'operatore esegue un diritto di spostamento logico in cui le posizioni di bit vuote di ordine elevato sono sempre impostate su zero.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. Per eseguire l'operazione opposta di quella dedotta dal tipo di operando, è possibile usare cast espliciti.To perform the opposite operation of that inferred from the operand type, explicit casts can be used. Se ad esempio x è una variabile di tipo int, l'operazione unchecked((int)((uint)x >> y)) esegue un diritto di spostamento logico di 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.

Operatori relazionali e operatori di test del tipoRelational and type-testing operators

Gli operatori ==, !=, <, >, <=, >=, is e as sono detti operatori relazionali e di test dei tipi.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
    ;

L'operatore is è descritto nell'operatore is e l'operatore as è descritto nell' operatore As.The is operator is described in The is operator and the as operator is described in The as operator.

Gli operatori ==, !=, <, >, <= e >= sono operatori di confronto.The ==, !=, <, >, <= and >= operators are comparison operators.

Se un operando di un operatore di confronto dispone del tipo in fase di compilazione dynamic, l'espressione viene associata dinamicamente (associazione dinamica).If an operand of a comparison operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). In questo caso il tipo in fase di compilazione dell'espressione viene dynamice la risoluzione descritta di seguito verrà eseguita in fase di esecuzione usando il tipo di runtime degli operandi che hanno il tipo in fase di compilazione 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.

Per un'operazione nel formato x op y, dove op è un operatore di confronto, viene applicata la risoluzione dell'overload (risoluzione dell'Overload degli operatori binari) per selezionare un'implementazione di operatore specifica.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. Gli operandi vengono convertiti nei tipi di parametro dell'operatore selezionato e il tipo del risultato è il tipo restituito dell'operatore.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.

Gli operatori di confronto predefiniti sono descritti nelle sezioni seguenti.The predefined comparison operators are described in the following sections. Tutti gli operatori di confronto predefiniti restituiscono un risultato di tipo bool, come descritto nella tabella seguente.All predefined comparison operators return a result of type bool, as described in the following table.

OperazioneOperation RisultatoResult
x == y true se x è uguale y, false in caso contrariotrue if x is equal to y, false otherwise
x != y true se x non è uguale a y, false in caso contrariotrue if x is not equal to y, false otherwise
x < y true se x è minore di y, false in caso contrariotrue if x is less than y, false otherwise
x > y true se x è maggiore di y, false in caso contrariotrue if x is greater than y, false otherwise
x <= y true se x è minore o uguale a y, false in caso contrariotrue if x is less than or equal to y, false otherwise
x >= y true se x è maggiore o uguale a y, false in caso contrariotrue if x is greater than or equal to y, false otherwise

Operatori di confronto integerInteger comparison operators

Gli operatori di confronto Integer predefiniti sono: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);

Ognuno di questi operatori confronta i valori numerici dei due operandi Integer e restituisce un valore bool che indica se la relazione specifica è true o 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.

Operatori di confronto a virgola mobileFloating-point comparison operators

Gli operatori di confronto a virgola mobile predefiniti sono: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);

Gli operatori confrontano gli operandi secondo le regole dello standard IEEE 754:The operators compare the operands according to the rules of the IEEE 754 standard:

  • Se uno degli operandi è NaN, il risultato viene false per tutti gli operatori eccetto !=, per il quale viene trueil risultato.If either operand is NaN, the result is false for all operators except !=, for which the result is true. Per due operandi qualsiasi, x != y produce sempre lo stesso risultato !(x == y).For any two operands, x != y always produces the same result as !(x == y). Tuttavia, quando uno o entrambi gli operandi sono NaN, gli operatori <, >, <=e >= non producono gli stessi risultati della negazione logica dell'operatore opposto.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. Ad esempio, se una delle x e y è NaN, x < y è false, ma !(x >= y) è true.For example, if either of x and y is NaN, then x < y is false, but !(x >= y) is true.

  • Quando nessuno degli operandi è NaN, gli operatori confrontano i valori dei due operandi a virgola mobile rispetto all'ordinamentoWhen 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
    

    dove min e max sono i valori finiti positivi più piccoli e più grandi che possono essere rappresentati nel formato a virgola mobile specificato.where min and max are the smallest and largest positive finite values that can be represented in the given floating-point format. Gli effetti significativi di questo ordine sono i seguenti:Notable effects of this ordering are:

    • Gli zeri negativi e positivi sono considerati uguali.Negative and positive zeros are considered equal.
    • Un infinito negativo è considerato minore di tutti gli altri valori, ma è uguale a un altro infinito negativo.A negative infinity is considered less than all other values, but equal to another negative infinity.
    • Un infinito positivo è considerato maggiore di tutti gli altri valori, ma uguale a un altro infinito positivo.A positive infinity is considered greater than all other values, but equal to another positive infinity.

Operatori di confronto decimaliDecimal comparison operators

Gli operatori di confronto decimali predefiniti sono: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);

Ognuno di questi operatori confronta i valori numerici dei due operandi decimali e restituisce un valore bool che indica se la relazione specifica è true o 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. Ogni confronto decimale equivale all'uso dell'operatore relazionale o di uguaglianza corrispondente di tipo System.Decimal.Each decimal comparison is equivalent to using the corresponding relational or equality operator of type System.Decimal.

Operatori di uguaglianza booleaniBoolean equality operators

Gli operatori di uguaglianza booleani predefiniti sono:The predefined boolean equality operators are:

bool operator ==(bool x, bool y);
bool operator !=(bool x, bool y);

Il risultato di == viene true se x e y sono true o se x e y sono false.The result of == is true if both x and y are true or if both x and y are false. In caso contrario, il risultato è false.Otherwise, the result is false.

Il risultato di != viene false se x e y sono true o se x e y sono false.The result of != is false if both x and y are true or if both x and y are false. In caso contrario, il risultato è true.Otherwise, the result is true. Quando gli operandi sono di tipo bool, l'operatore != produce lo stesso risultato dell'operatore ^.When the operands are of type bool, the != operator produces the same result as the ^ operator.

Operatori di confronto di enumerazioneEnumeration comparison operators

Ogni tipo di enumerazione fornisce in modo implicito gli operatori di confronto predefiniti seguenti: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);

Il risultato della valutazione x op y, in cui x e y sono espressioni di un tipo di enumerazione E con un tipo sottostante Ue op è uno degli operatori di confronto, è esattamente uguale alla valutazione di ((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 altre parole, gli operatori di confronto del tipo di enumerazione confrontano semplicemente i valori integrali sottostanti dei due operandi.In other words, the enumeration type comparison operators simply compare the underlying integral values of the two operands.

Operatori di uguaglianza del tipo di riferimentoReference type equality operators

Gli operatori di uguaglianza del tipo di riferimento predefiniti sono:The predefined reference type equality operators are:

bool operator ==(object x, object y);
bool operator !=(object x, object y);

Gli operatori restituiscono il risultato del confronto tra i due riferimenti per verificarne l'uguaglianza o la mancata uguaglianza.The operators return the result of comparing the two references for equality or non-equality.

Poiché gli operatori di uguaglianza del tipo di riferimento predefiniti accettano operandi di tipo object, si applicano a tutti i tipi che non dichiarano i membri operator == e operator != applicabili.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. Viceversa, gli operatori di uguaglianza definiti dall'utente applicabili nascondono efficacemente gli operatori di uguaglianza del tipo di riferimento predefiniti.Conversely, any applicable user-defined equality operators effectively hide the predefined reference type equality operators.

Gli operatori di uguaglianza del tipo di riferimento predefiniti richiedono uno dei seguenti elementi:The predefined reference type equality operators require one of the following:

  • Entrambi gli operandi sono un valore di un tipo noto come reference_type o nullletterale.Both operands are a value of a type known to be a reference_type or the literal null. Inoltre, esiste una conversione esplicita del riferimento (conversioni esplicite di riferimento) dal tipo di uno degli operandi al tipo dell'altro operando.Furthermore, an explicit reference conversion (Explicit reference conversions) exists from the type of either operand to the type of the other operand.
  • Un operando è un valore di tipo T dove T è un type_parameter e l'altro operando è il valore letterale null.One operand is a value of type T where T is a type_parameter and the other operand is the literal null. Inoltre T non dispone del vincolo di tipo valore.Furthermore T does not have the value type constraint.

A meno che una di queste condizioni non sia vera, si verifica un errore in fase di binding.Unless one of these conditions are true, a binding-time error occurs. Le implicazioni rilevanti di queste regole sono:Notable implications of these rules are:

  • Si tratta di un errore in fase di binding per usare gli operatori di uguaglianza del tipo di riferimento predefiniti per confrontare due riferimenti che sono noti come diversi in fase di binding.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. Se, ad esempio, i tipi in fase di binding degli operandi sono due tipi di classe A e Be se nessuno dei due AB deriva dall'altro, non sarebbe possibile che i due operandi facciano riferimento allo stesso oggetto.For example, if the binding-time types of the operands are two class types A and B, and if neither A nor B derives from the other, then it would be impossible for the two operands to reference the same object. L'operazione viene pertanto considerata un errore in fase di binding.Thus, the operation is considered a binding-time error.
  • Gli operatori di uguaglianza del tipo di riferimento predefiniti non consentono il confronto degli operandi dei tipi di valore.The predefined reference type equality operators do not permit value type operands to be compared. Pertanto, a meno che un tipo struct non dichiari i propri operatori di uguaglianza, non è possibile confrontare i valori di tale tipo di struct.Therefore, unless a struct type declares its own equality operators, it is not possible to compare values of that struct type.
  • Gli operatori di uguaglianza del tipo di riferimento predefiniti non provocano mai operazioni di conversione boxing per i rispettivi operandi.The predefined reference type equality operators never cause boxing operations to occur for their operands. Sarebbe inutile eseguire tali operazioni di conversione boxing, dal momento che i riferimenti alle istanze boxed appena allocate sarebbero necessariamente diversi da tutti gli altri riferimenti.It would be meaningless to perform such boxing operations, since references to the newly allocated boxed instances would necessarily differ from all other references.
  • Se un operando di un tipo di parametro di tipo T viene confrontato con nulle il tipo in fase di esecuzione di T è un tipo di valore, il risultato del confronto viene false.If an operand of a type parameter type T is compared to null, and the run-time type of T is a value type, the result of the comparison is false.

Nell'esempio seguente viene controllato se un argomento di un tipo di parametro di tipo non vincolato è 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();
        ...
    }
}

Il costrutto x == null è consentito anche se T può rappresentare un tipo di valore e il risultato viene semplicemente definito false quando T è un tipo valore.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.

Per un'operazione nel formato x == y o x != y, se è presente un operator == o operator != applicabile, le regole di risoluzione dell'overload dell'operatore (risoluzione dell'overload dell'operatore binario) selezioneranno tale operatore anziché l'operatore di uguaglianza del tipo di riferimento predefinito.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. Tuttavia, è sempre possibile selezionare l'operatore di uguaglianza del tipo di riferimento predefinito eseguendo il cast esplicito di uno o entrambi gli operandi al tipo 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. EsempioThe 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);
    }
}

produce l'outputproduces the output

True
False
False
False

Le variabili s e t fanno riferimento a due istanze di string distinte contenenti gli stessi caratteri.The s and t variables refer to two distinct string instances containing the same characters. Il primo output del confronto True perché l'operatore di uguaglianza di stringa predefinito (operatori di uguaglianza di stringa) viene selezionato quando entrambi gli operandi sono di tipo string.The first comparison outputs True because the predefined string equality operator (String equality operators) is selected when both operands are of type string. Gli altri confronti False di output poiché l'operatore di uguaglianza del tipo di riferimento predefinito è selezionato quando uno o entrambi gli operandi sono di tipo 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.

Si noti che la tecnica precedente non è significativa per i tipi di valore.Note that the above technique is not meaningful for value types. EsempioThe example

class Test
{
    static void Main() {
        int i = 123;
        int j = 123;
        System.Console.WriteLine((object)i == (object)j);
    }
}

Restituisce False perché i cast creano riferimenti a due istanze separate di valori di int boxed.outputs False because the casts create references to two separate instances of boxed int values.

Operatori di uguaglianza delle stringheString equality operators

Gli operatori di uguaglianza di stringa predefiniti sono:The predefined string equality operators are:

bool operator ==(string x, string y);
bool operator !=(string x, string y);

Due string valori sono considerati uguali quando si verifica una delle condizioni seguenti:Two string values are considered equal when one of the following is true:

  • Entrambi i valori sono null.Both values are null.
  • Entrambi i valori sono riferimenti non null alle istanze di stringa con lunghezze identiche e caratteri identici in ogni posizione del carattere.Both values are non-null references to string instances that have identical lengths and identical characters in each character position.

Gli operatori di uguaglianza di stringa confrontano i valori stringa anziché i riferimenti di stringa.The string equality operators compare string values rather than string references. Quando due istanze di stringa separate contengono esattamente la stessa sequenza di caratteri, i valori delle stringhe sono uguali, ma i riferimenti sono diversi.When two separate string instances contain the exact same sequence of characters, the values of the strings are equal, but the references are different. Come descritto in operatori di uguaglianza dei tipi di riferimento, gli operatori di uguaglianza del tipo di riferimento possono essere usati per confrontare i riferimenti di stringa anziché i valori stringa.As described in Reference type equality operators, the reference type equality operators can be used to compare string references instead of string values.

Operatori di uguaglianza delegatiDelegate equality operators

Ogni tipo delegato fornisce in modo implicito gli operatori di confronto predefiniti seguenti: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);

Due istanze delegate sono considerate uguali, come indicato di seguito:Two delegate instances are considered equal as follows:

  • Se una delle istanze delegate è null, sono uguali se e solo se entrambe sono null.If either of the delegate instances is null, they are equal if and only if both are null.
  • Se i delegati hanno un tipo diverso in fase di esecuzione, non sono mai uguali.If the delegates have different run-time type they are never equal.
  • Se entrambe le istanze del delegato hanno un elenco chiamate (dichiarazioni di Delegate), tali istanze sono uguali se e solo se i relativi elenchi chiamate hanno la stessa lunghezza e ogni voce in un elenco chiamate è uguale (come definito di seguito) alla voce corrispondente, nell'ordine, nell'elenco chiamate dell'altro.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.

Le regole seguenti regolano l'uguaglianza delle voci dell'elenco chiamate:The following rules govern the equality of invocation list entries:

  • Se due voci dell'elenco chiamate si riferiscono entrambi allo stesso metodo statico, le voci sono uguali.If two invocation list entries both refer to the same static method then the entries are equal.
  • Se due voci dell'elenco chiamate fanno riferimento allo stesso metodo non statico sullo stesso oggetto di destinazione (come definito dagli operatori di uguaglianza dei riferimenti), le voci sono uguali.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.
  • Le voci dell'elenco chiamate generate dalla valutazione di anonymous_method_expressiono lambda_expressions semanticamente identiche con lo stesso set (possibilmente vuoto) di istanze di variabili esterne acquisite sono consentite (ma non necessarie) uguali.Invocation list entries produced from evaluation of semantically identical anonymous_method_expressions or lambda_expressions with the same (possibly empty) set of captured outer variable instances are permitted (but not required) to be equal.

Operatori di uguaglianza e nullEquality operators and null

Gli operatori == e != consentono a un operando di essere un valore di un tipo nullable e l'altro come null valore letterale, anche se non è presente alcun operatore predefinito o definito dall'utente (in formato non elevato o Lift) per l'operazione.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.

Per un'operazione di uno dei formFor an operation of one of the forms

x == null
null == x
x != null
null != x

dove x è un'espressione di un tipo nullable, se la risoluzione dell'overload dell'operatore (risoluzione dell'overload dell'operatore binario) non riesce a trovare un operatore applicabile, il risultato viene invece calcolato dalla proprietà HasValue di 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. In particolare, le prime due forme vengono convertite in !x.HasValuee le ultime due forme vengono convertite in x.HasValue.Specifically, the first two forms are translated into !x.HasValue, and last two forms are translated into x.HasValue.

Operatore isThe is operator

L'operatore is viene utilizzato per controllare dinamicamente se il tipo di runtime di un oggetto è compatibile con un tipo specificato.The is operator is used to dynamically check if the run-time type of an object is compatible with a given type. Il risultato dell'operazione E is T, dove E è un'espressione e T è un tipo, è un valore booleano che indica se E può essere convertito correttamente nel tipo T da una conversione di riferimento, una conversione boxing o una conversione unboxing.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. L'operazione viene valutata come segue, dopo che gli argomenti di tipo sono stati sostituiti per tutti i parametri di tipo:The operation is evaluated as follows, after type arguments have been substituted for all type parameters:

  • Se E è una funzione anonima, si verifica un errore in fase di compilazioneIf E is an anonymous function, a compile-time error occurs
  • Se E è un gruppo di metodi o il valore letterale null, se il tipo di E è un tipo di riferimento o un tipo nullable e il valore di E è null, il risultato è false.If E is a method group or the null literal, of if the type of E is a reference type or a nullable type and the value of E is null, the result is false.
  • In caso contrario, consentire D rappresentare il tipo dinamico di E come segue:Otherwise, let D represent the dynamic type of E as follows:
    • Se il tipo di E è un tipo di riferimento, D è il tipo in fase di esecuzione del riferimento all'istanza da E.If the type of E is a reference type, D is the run-time type of the instance reference by E.
    • Se il tipo di E è un tipo nullable, D è il tipo sottostante di tale tipo Nullable.If the type of E is a nullable type, D is the underlying type of that nullable type.
    • Se il tipo di E è un tipo di valore non nullable, D è il tipo di E.If the type of E is a non-nullable value type, D is the type of E.
  • Il risultato dell'operazione dipende da D e T, come indicato di seguito:The result of the operation depends on D and T as follows:
    • Se T è un tipo di riferimento, il risultato è true se D e T sono dello stesso tipo, se D è un tipo di riferimento e la conversione implicita di un riferimento da D a T esiste o se D è un tipo di valore ed è presente una conversione boxing da D a T esistente.If T is a reference type, the result is true if D and T are the same type, if D is a reference type and an implicit reference conversion from D to T exists, or if D is a value type and a boxing conversion from D to T exists.
    • Se T è un tipo nullable, il risultato è true se D è il tipo sottostante di T.If T is a nullable type, the result is true if D is the underlying type of T.
    • Se T è un tipo di valore non nullable, il risultato è true se D e T sono dello stesso tipo.If T is a non-nullable value type, the result is true if D and T are the same type.
    • In caso contrario, il risultato è false.Otherwise, the result is false.

Si noti che le conversioni definite dall'utente non vengono considerate dall'operatore is.Note that user defined conversions, are not considered by the is operator.

Operatore AsThe as operator

L'operatore as viene utilizzato per convertire in modo esplicito un valore in un tipo di riferimento o un tipo nullable specificato.The as operator is used to explicitly convert a value to a given reference type or nullable type. A differenza di un'espressione cast (espressioni cast), l'operatore as non genera mai un'eccezione.Unlike a cast expression (Cast expressions), the as operator never throws an exception. Se invece la conversione indicata non è possibile, il valore risultante viene null.Instead, if the indicated conversion is not possible, the resulting value is null.

In un'operazione nel formato E as T, E deve essere un'espressione e T deve essere un tipo di riferimento, un parametro di tipo noto come tipo di riferimento o un tipo Nullable.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. Inoltre, almeno uno dei seguenti elementi deve essere true o in caso contrario si verifica un errore in fase di compilazione:Furthermore, at least one of the following must be true, or otherwise a compile-time error occurs:

Se il tipo di E in fase di compilazione non è dynamic, l'operazione E as T produce lo stesso risultato diIf 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

con la differenza che E viene valutato una sola volta.except that E is only evaluated once. Si può prevedere che il compilatore ottimizzi E as T per eseguire al massimo un controllo del tipo dinamico, anziché i due controlli dei tipi dinamici implicati dall'espansione precedente.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.

Se il tipo in fase di compilazione di E è dynamic, a differenza dell'operatore cast, l'operatore as non è associato in modo dinamico (associazione dinamica).If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound (Dynamic binding). Quindi, in questo caso, l'espansione è:Therefore the expansion in this case is:

E is T ? (T)(object)(E) : (T)null

Si noti che alcune conversioni, ad esempio le conversioni definite dall'utente, non sono possibili con l'operatore as e devono invece essere eseguite mediante espressioni 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.

Nell'esempioIn 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 
    }
}

il parametro di tipo T di G è noto come tipo di riferimento, perché contiene il vincolo di classe.the type parameter T of G is known to be a reference type, because it has the class constraint. Il parametro di tipo U di H non è tuttavia; di conseguenza, l'uso dell'operatore as in H non è consentito.The type parameter U of H is not however; hence the use of the as operator in H is disallowed.

Operatori logiciLogical operators

Gli operatori &, ^e | sono detti operatori logici.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
    ;

Se un operando di un operatore logico dispone del tipo in fase di compilazione dynamic, l'espressione viene associata dinamicamente (associazione dinamica).If an operand of a logical operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). In questo caso il tipo in fase di compilazione dell'espressione viene dynamice la risoluzione descritta di seguito verrà eseguita in fase di esecuzione usando il tipo di runtime degli operandi che hanno il tipo in fase di compilazione 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.

Per un'operazione con il formato x op y, dove op è uno degli operatori logici, viene applicata la risoluzione dell'overload (risoluzione dell'overload dell'operatore binario) per selezionare un'implementazione specifica dell'operatore.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. Gli operandi vengono convertiti nei tipi di parametro dell'operatore selezionato e il tipo del risultato è il tipo restituito dell'operatore.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.

Gli operatori logici predefiniti sono descritti nelle sezioni seguenti.The predefined logical operators are described in the following sections.

Operatori logici integerInteger logical operators

Gli operatori logici integer predefiniti sono: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);

L'operatore & calcola la AND logica bit per bit dei due operandi, l'operatore | calcola la OR logica bit per bit dei due operandi e l'operatore di ^ calcola l'OR esclusiva logica bit per bit dei due operandi.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. Non sono possibili overflow da queste operazioni.No overflows are possible from these operations.

Operatori logici di enumerazioneEnumeration logical operators

Ogni tipo di enumerazione E fornisce in modo implicito gli operatori logici predefiniti seguenti: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);

Il risultato della valutazione x op y, in cui x e y sono espressioni di un tipo di enumerazione E con un tipo sottostante Ue op è uno degli operatori logici, è esattamente uguale alla valutazione di (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 altre parole, gli operatori logici di tipo enumerazione eseguono semplicemente l'operazione logica sul tipo sottostante dei due operandi.In other words, the enumeration type logical operators simply perform the logical operation on the underlying type of the two operands.

Operatori logici booleaniBoolean logical operators

Gli operatori logici booleani predefiniti sono:The predefined boolean logical operators are:

bool operator &(bool x, bool y);
bool operator |(bool x, bool y);
bool operator ^(bool x, bool y);

Il risultato di x & y è true se x e y sono true.The result of x & y is true if both x and y are true. In caso contrario, il risultato è false.Otherwise, the result is false.

Il risultato di x | y viene true se x o y è true.The result of x | y is true if either x or y is true. In caso contrario, il risultato è false.Otherwise, the result is false.

Il risultato di x ^ y viene true se x è true e y è falseoppure x è false e 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. In caso contrario, il risultato è false.Otherwise, the result is false. Quando gli operandi sono di tipo bool, l'operatore ^ calcola lo stesso risultato dell'operatore !=.When the operands are of type bool, the ^ operator computes the same result as the != operator.

Operatori logici booleani nullableNullable boolean logical operators

Il tipo booleano nullable bool? può rappresentare tre valori, true, falsee nulled è concettualmente simile al tipo a tre valori usato per le espressioni booleane in 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. Per garantire che i risultati prodotti dagli operatori & e | per gli operandi bool? siano coerenti con la logica a tre valori di SQL, vengono forniti gli operatori predefiniti seguenti: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);

Nella tabella seguente sono elencati i risultati ottenuti da questi operatori per tutte le combinazioni dei valori true, falsee 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

Operatori logici condizionaliConditional logical operators

Gli operatori && e || sono detti operatori logici condizionali.The && and || operators are called the conditional logical operators. Sono detti anche operatori logici di "corto circuito".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
    ;

Gli operatori && e || sono versioni condizionali degli operatori & e |:The && and || operators are conditional versions of the & and | operators:

  • L'operazione x && y corrisponde al x & ydell'operazione, ad eccezione del fatto che y viene valutato solo se x non è false.The operation x && y corresponds to the operation x & y, except that y is evaluated only if x is not false.
  • L'operazione x || y corrisponde al x | ydell'operazione, ad eccezione del fatto che y viene valutato solo se x non è true.The operation x || y corresponds to the operation x | y, except that y is evaluated only if x is not true.

Se un operando di un operatore logico condizionale ha il tipo in fase di compilazione dynamic, l'espressione viene associata dinamicamente (associazione dinamica).If an operand of a conditional logical operator has the compile-time type dynamic, then the expression is dynamically bound (Dynamic binding). In questo caso il tipo in fase di compilazione dell'espressione viene dynamice la risoluzione descritta di seguito verrà eseguita in fase di esecuzione usando il tipo di runtime degli operandi che hanno il tipo in fase di compilazione 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.

Un'operazione del form x && y o x || y viene elaborata applicando la risoluzione dell'overload (risoluzione dell'overload dell'operatore binario) come se l'operazione fosse stata scritta x & y o 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. Con questi presupposti,Then,

Non è possibile eseguire direttamente l'overload degli operatori logici condizionali.It is not possible to directly overload the conditional logical operators. Tuttavia, poiché gli operatori logici condizionali vengono valutati in termini di operatori logici normali, gli overload degli operatori logici normali sono, con alcune restrizioni, considerati anche gli overload degli operatori logici condizionali.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. Questa operazione viene descritta in modo più approfondito negli operatori logici condizionali definiti dall'utente.This is described further in User-defined conditional logical operators.

Operatori logici condizionali booleaniBoolean conditional logical operators

Quando gli operandi di && o || sono di tipo boolo quando gli operandi sono di tipi che non definiscono un operator & o operator |applicabile, ma definiscono le conversioni implicite per bool, l'operazione viene elaborata come segue: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:

  • L'operazione x && y viene valutata come x ? y : false.The operation x && y is evaluated as x ? y : false. In altre parole, x viene prima valutata e convertita nel tipo bool.In other words, x is first evaluated and converted to type bool. Quindi, se x viene true, y viene valutata e convertita nel tipo boole questo diventa il risultato dell'operazione.Then, if x is true, y is evaluated and converted to type bool, and this becomes the result of the operation. In caso contrario, il risultato dell'operazione è false.Otherwise, the result of the operation is false.
  • L'operazione x || y viene valutata come x ? true : y.The operation x || y is evaluated as x ? true : y. In altre parole, x viene prima valutata e convertita nel tipo bool.In other words, x is first evaluated and converted to type bool. Quindi, se x è true, il risultato dell'operazione è true.Then, if x is true, the result of the operation is true. In caso contrario, y viene valutata e convertita nel tipo bool, che diventa il risultato dell'operazione.Otherwise, y is evaluated and converted to type bool, and this becomes the result of the operation.

Operatori logici condizionali definiti dall'utenteUser-defined conditional logical operators

Quando gli operandi di && o || sono di tipo che dichiarano un operator & o un operator |definito dall'utente applicabile, devono essere soddisfatte entrambe le condizioni seguenti, dove T è il tipo in cui viene dichiarato l'operatore selezionato: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:

  • Il tipo restituito e il tipo di ogni parametro dell'operatore selezionato devono essere T.The return type and the type of each parameter of the selected operator must be T. In altre parole, l'operatore deve calcolare il AND logico o la OR logica di due operandi di tipo Te deve restituire un risultato di tipo T.In other words, the operator must compute the logical AND or the logical OR of two operands of type T, and must return a result of type T.
  • T deve contenere dichiarazioni di operator true e operator false.T must contain declarations of operator true and operator false.

Si verifica un errore in fase di binding se uno di questi requisiti non è soddisfatto.A binding-time error occurs if either of these requirements is not satisfied. In caso contrario, l'operazione di && o || viene valutata combinando il operator true definito dall'utente o operator false con l'operatore definito dall'utente selezionato:Otherwise, the && or || operation is evaluated by combining the user-defined operator true or operator false with the selected user-defined operator:

  • L'operazione x && y viene valutata come T.false(x) ? x : T.&(x, y), in cui T.false(x) è una chiamata della operator false dichiarata in Te T.&(x, y) è una chiamata del operator &selezionato.The operation x && y is evaluated as T.false(x) ? x : T.&(x, y), where T.false(x) is an invocation of the operator false declared in T, and T.&(x, y) is an invocation of the selected operator &. In altre parole, x viene valutata per la prima volta e viene richiamato operator false sul risultato per determinare se x è decisamente false.In other words, x is first evaluated and operator false is invoked on the result to determine if x is definitely false. Se x è sicuramente false, il risultato dell'operazione è il valore calcolato in precedenza per x.Then, if x is definitely false, the result of the operation is the value previously computed for x. In caso contrario, viene valutato y e il operator & selezionato viene richiamato sul valore calcolato in precedenza per x e il valore calcolato per y per produrre il risultato dell'operazione.Otherwise, y is evaluated, and the selected operator & is invoked on the value previously computed for x and the value computed for y to produce the result of the operation.
  • L'operazione x || y viene valutata come T.true(x) ? x : T.|(x, y), in cui T.true(x) è una chiamata della operator true dichiarata in Te T.|(x,y) è una chiamata del operator|selezionato.The operation x || y is evaluated as T.true(x) ? x : T.|(x, y), where T.true(x) is an invocation of the operator true declared in T, and T.|(x,y) is an invocation of the selected operator|. In altre parole, x viene valutata per la prima volta e viene richiamato operator true sul risultato per determinare se x è sicuramente true.In other words, x is first evaluated and operator true is invoked on the result to determine if x is definitely true. Se x è sicuramente true, il risultato dell'operazione è il valore calcolato in precedenza per x.Then, if x is definitely true, the result of the operation is the value previously computed for x. In caso contrario, viene valutato y e il operator | selezionato viene richiamato sul valore calcolato in precedenza per x e il valore calcolato per y per produrre il risultato dell'operazione.Otherwise, y is evaluated, and the selected operator | is invoked on the value previously computed for x and the value computed for y to produce the result of the operation.

In una di queste operazioni, l'espressione fornita da x viene valutata una sola volta e l'espressione fornita da y non viene valutata o valutata esattamente una volta.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.

Per un esempio di un tipo che implementa operator true e operator false, vedere database Boolean type.For an example of a type that implements operator true and operator false, see Database boolean type.

Operatore di Unione nullThe null coalescing operator

L'operatore ?? viene chiamato operatore di Unione null.The ?? operator is called the null coalescing operator.

null_coalescing_expression
    : conditional_or_expression
    | conditional_or_expression '??' null_coalescing_expression
    ;

Un'espressione di Unione null nel formato a ?? b richiede che a sia di un tipo di riferimento o un tipo Nullable.A null coalescing expression of the form a ?? b requires a to be of a nullable type or reference type. Se a è diverso da null, il risultato di a ?? b è a; in caso contrario, il risultato è b.If a is non-null, the result of a ?? b is a; otherwise, the result is b. L'operazione valuta b solo se a è null.The operation evaluates b only if a is null.

L'operatore di Unione null è associato a destra, ovvero le operazioni sono raggruppate da destra a sinistra.The null coalescing operator is right-associative, meaning that operations are grouped from right to left. Ad esempio, un'espressione nel formato a ?? b ?? c viene valutata come a ?? (b ?? c).For example, an expression of the form a ?? b ?? c is evaluated as a ?? (b ?? c). In termini generali, un'espressione nel formato E1 ?? E2 ?? ... ?? En restituisce il primo degli operandi che è non null o null se tutti gli operandi sono 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.

Il tipo di espressione a ?? b dipende da quali conversioni implicite sono disponibili negli operandi.The type of the expression a ?? b depends on which implicit conversions are available on the operands. In ordine di preferenza, il tipo di a ?? b è A0, Ao B, dove A è il tipo di a (purché a disponga di un tipo), B è il tipo di b (purché b disponga di un tipo) e A0 è il tipo sottostante di A se A è un tipo nullable o A in caso contrario.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. In particolare, a ?? b viene elaborato come segue:Specifically, a ?? b is processed as follows:

  • Se A esiste e non è un tipo nullable o un tipo riferimento, si verifica un errore in fase di compilazione.If A exists and is not a nullable type or a reference type, a compile-time error occurs.
  • Se b è un'espressione dinamica, il tipo di risultato è dynamic.If b is a dynamic expression, the result type is dynamic. In fase di esecuzione a viene valutata per la prima volta.At run-time, a is first evaluated. Se a non è null, a viene convertito in Dynamic e questo diventa il risultato.If a is not null, a is converted to dynamic, and this becomes the result. In caso contrario, b viene valutato e questo diventa il risultato.Otherwise, b is evaluated, and this becomes the result.
  • In caso contrario, se A esiste ed è un tipo Nullable ed esiste una conversione implicita da b a A0, il tipo di risultato sarà A0.Otherwise, if A exists and is a nullable type and an implicit conversion exists from b to A0, the result type is A0. In fase di esecuzione a viene valutata per la prima volta.At run-time, a is first evaluated. Se a non è null, viene annullato il wrapper a per il tipo A0e questo diventa il risultato.If a is not null, a is unwrapped to type A0, and this becomes the result. In caso contrario, b viene valutata e convertita nel tipo A0, che diventa il risultato.Otherwise, b is evaluated and converted to type A0, and this becomes the result.
  • In caso contrario, se A esiste ed esiste una conversione implicita da b a A, il tipo di risultato sarà A.Otherwise, if A exists and an implicit conversion exists from b to A, the result type is A. In fase di esecuzione a viene valutata per la prima volta.At run-time, a is first evaluated. Se a non è null, a diventa il risultato.If a is not null, a becomes the result. In caso contrario, b viene valutata e convertita nel tipo A, che diventa il risultato.Otherwise, b is evaluated and converted to type A, and this becomes the result.
  • In caso contrario, se b dispone di un tipo B ed esiste una conversione implicita da a a B, il tipo di risultato sarà B.Otherwise, if b has a type B and an implicit conversion exists from a to B, the result type is B. In fase di esecuzione a viene valutata per la prima volta.At run-time, a is first evaluated. Se a non è null, viene annullato il wrapper a per il tipo A0 (se A esiste e ammette valori null) e viene convertito nel tipo Be questo diventa il risultato.If a is not null, a is unwrapped to type A0 (if A exists and is nullable) and converted to type B, and this becomes the result. In caso contrario, b viene valutato e diventa il risultato.Otherwise, b is evaluated and becomes the result.
  • In caso contrario, a e b sono incompatibili e si verifica un errore in fase di compilazione.Otherwise, a and b are incompatible, and a compile-time error occurs.

Operatore condizionaleConditional operator

L'operatore ?: viene chiamato operatore condizionale.The ?: operator is called the conditional operator. Viene anche chiamato operatore ternario.It is at times also called the ternary operator.

conditional_expression
    : null_coalescing_expression
    | null_coalescing_expression '?' expression ':' expression
    ;

Un'espressione condizionale del form b ? x : y per prima cosa valuta la condizione b.A conditional expression of the form b ? x : y first evaluates the condition b. Quindi, se b è true, x viene valutato e diventa il risultato dell'operazione.Then, if b is true, x is evaluated and becomes the result of the operation. In caso contrario, y viene valutato e diventa il risultato dell'operazione.Otherwise, y is evaluated and becomes the result of the operation. Un'espressione condizionale non valuta mai sia x che y.A conditional expression never evaluates both x and y.

L'operatore condizionale è associato a destra, ovvero le operazioni sono raggruppate da destra a sinistra.The conditional operator is right-associative, meaning that operations are grouped from right to left. Ad esempio, un'espressione nel formato a ? b : c ? d : e viene valutata come 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).

Il primo operando dell'operatore di ?: deve essere un'espressione che può essere convertita in modo implicito in boolo un'espressione di un tipo che implementa 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. Se nessuno di questi requisiti viene soddisfatto, si verifica un errore in fase di compilazione.If neither of these requirements is satisfied, a compile-time error occurs.

Il secondo e il terzo operando, x e y, dell'operatore ?: controllano il tipo di espressione condizionale.The second and third operands, x and y, of the ?: operator control the type of the conditional expression.

  • Se x è di tipo X e y è di tipo YIf x has type X and y has type Y then
    • Se esiste una conversione implicita (conversioni implicite) da X a Y, ma non da Y a X, Y è il tipo dell'espressione condizionale.If an implicit conversion (Implicit conversions) exists from X to Y, but not from Y to X, then Y is the type of the conditional expression.
    • Se esiste una conversione implicita (conversioni implicite) da Y a X, ma non da X a Y, X è il tipo dell'espressione condizionale.If an implicit conversion (Implicit conversions) exists from Y to X, but not from X to Y, then X is the type of the conditional expression.
    • In caso contrario, non è possibile determinare alcun tipo di espressione e si verifica un errore in fase di compilazione.Otherwise, no expression type can be determined, and a compile-time error occurs.
  • Se solo uno dei x e y dispone di un tipo e sia x che y, di sono convertibili in modo implicito in tale tipo, ovvero il tipo dell'espressione condizionale.If only one of x and y has a type, and both x and y, of are implicitly convertible to that type, then that is the type of the conditional expression.
  • In caso contrario, non è possibile determinare alcun tipo di espressione e si verifica un errore in fase di compilazione.Otherwise, no expression type can be determined, and a compile-time error occurs.

L'elaborazione in fase di esecuzione di un'espressione condizionale nel formato b ? x : y prevede i passaggi seguenti:The run-time processing of a conditional expression of the form b ? x : y consists of the following steps:

  • Viene innanzitutto valutato b e viene determinato il valore bool di b:First, b is evaluated, and the bool value of b is determined:
    • Se esiste una conversione implicita dal tipo di b al bool, questa conversione implicita viene eseguita per produrre un valore di bool.If an implicit conversion from the type of b to bool exists, then this implicit conversion is performed to produce a bool value.
    • In caso contrario, il operator true definito dal tipo di b viene richiamato per produrre un valore di bool.Otherwise, the operator true defined by the type of b is invoked to produce a bool value.
  • Se il valore bool prodotto dal passaggio precedente è true, x viene valutato e convertito nel tipo dell'espressione condizionale e diventa il risultato dell'espressione condizionale.If the bool value produced by the step above is true, then x is evaluated and converted to the type of the conditional expression, and this becomes the result of the conditional expression.
  • In caso contrario, y viene valutato e convertito nel tipo dell'espressione condizionale, che diventa il risultato dell'espressione condizionale.Otherwise, y is evaluated and converted to the type of the conditional expression, and this becomes the result of the conditional expression.

Espressioni di funzioni anonimeAnonymous function expressions

Una funzione anonima è un'espressione che rappresenta una definizione di metodo "inline".An anonymous function is an expression that represents an "in-line" method definition. Una funzione anonima non dispone di un valore o di un tipo in e di se stesso, ma è convertibile in un tipo di albero delle espressioni o di delegato compatibile.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. La valutazione di una conversione di funzione anonima dipende dal tipo di destinazione della conversione: se è un tipo delegato, la conversione restituisce un valore delegato che fa riferimento al metodo definito dalla funzione anonima.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. Se è un tipo di albero delle espressioni, la conversione restituisce un albero delle espressioni che rappresenta la struttura del metodo come struttura dell'oggetto.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.

Per motivi cronologici sono disponibili due versioni sintattiche di funzioni anonime, ovvero lambda_expressions e anonymous_method_expressions.For historical reasons there are two syntactic flavors of anonymous functions, namely lambda_expressions and anonymous_method_expressions. Per quasi tutti gli scopi, lambda_expressions sono più concisi ed espressivi rispetto a anonymous_method_expressions, che restano nella lingua per la compatibilità con le versioni precedenti.For almost all purposes, lambda_expressions are more concise and expressive than anonymous_method_expressions, 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
    ;

L'operatore => ha la stessa precedenza dell'assegnazione (=) ed è associativo a destra.The => operator has the same precedence as assignment (=) and is right-associative.

Una funzione anonima con il modificatore async è una funzione asincrona e segue le regole descritte negli iteratori.An anonymous function with the async modifier is an async function and follows the rules described in Iterators.

I parametri di una funzione anonima sotto forma di lambda_expression possono essere tipizzati in modo esplicito o implicito.The parameters of an anonymous function in the form of a lambda_expression can be explicitly or implicitly typed. In un elenco di parametri tipizzato in modo esplicito, il tipo di ogni parametro viene dichiarato in modo esplicito.In an explicitly typed parameter list, the type of each parameter is explicitly stated. In un elenco di parametri tipizzato in modo implicito, i tipi di parametri vengono dedotti dal contesto in cui si verifica la funzione anonima, in particolare quando la funzione anonima viene convertita in un tipo di delegato compatibile o in un tipo di albero delle espressioni, tale tipo fornisce i tipi di parametro (conversioni di funzioni anonime).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 una funzione anonima con un singolo parametro tipizzato in modo implicito, le parentesi possono essere omesse dall'elenco di parametri.In an anonymous function with a single, implicitly typed parameter, the parentheses may be omitted from the parameter list. In altre parole, una funzione anonima del formIn other words, an anonymous function of the form

( param ) => expr

può essere abbreviato incan be abbreviated to

param => expr

L'elenco di parametri di una funzione anonima sotto forma di anonymous_method_expression è facoltativo.The parameter list of an anonymous function in the form of an anonymous_method_expression is optional. Se specificato, i parametri devono essere tipizzati in modo esplicito.If given, the parameters must be explicitly typed. In caso contrario, la funzione anonima può essere convertita in un delegato con un elenco di parametri che non contiene out parametri.If not, the anonymous function is convertible to a delegate with any parameter list not containing out parameters.

Il corpo di un blocco di una funzione anonima è raggiungibile (punti finali e raggiungibilità), a meno che la funzione anonima non venga eseguita all'interno di un'istruzione non raggiungibile.A block body of an anonymous function is reachable (End points and reachability) unless the anonymous function occurs inside an unreachable statement.

Di seguito sono riportati alcuni esempi di funzioni anonime: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

Il comportamento di lambda_expressions e anonymous_method_expressions è identico ad eccezione dei punti seguenti:The behavior of lambda_expressions and anonymous_method_expressions is the same except for the following points:

  • anonymous_method_expressions consentono di omettere completamente l'elenco di parametri, restituendo la convertibilità ai tipi delegati di qualsiasi elenco di parametri di valore.anonymous_method_expressions permit the parameter list to be omitted entirely, yielding convertibility to delegate types of any list of value parameters.
  • lambda_expressions consentono di omettere e dedurre i tipi di parametro mentre anonymous_method_expressions richiedono che i tipi di parametro siano specificati in modo esplicito.lambda_expressions permit parameter types to be omitted and inferred whereas anonymous_method_expressions require parameter types to be explicitly stated.
  • Il corpo di un lambda_expression può essere un'espressione o un blocco di istruzioni, mentre il corpo di un anonymous_method_expression deve essere un blocco di istruzioni.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.
  • Solo lambda_expressions hanno conversioni a tipi di albero delle espressioni compatibili (tipi di albero delle espressioni).Only lambda_expressions have conversions to compatible expression tree types (Expression tree types).

Firme di funzioni anonimeAnonymous function signatures

Il anonymous_function_signature facoltativo di una funzione anonima definisce i nomi e, facoltativamente, i tipi di parametri formali per la funzione anonima.The optional anonymous_function_signature of an anonymous function defines the names and optionally the types of the formal parameters for the anonymous function. L'ambito dei parametri della funzione anonima è la anonymous_function_body.The scope of the parameters of the anonymous function is the anonymous_function_body. (Ambiti) Insieme all'elenco dei parametri (se specificato), il corpo del metodo anonimo costituisce uno spazio di dichiarazione (dichiarazioni).(Scopes) Together with the parameter list (if given) the anonymous-method-body constitutes a declaration space (Declarations). Si tratta quindi di un errore in fase di compilazione per il nome di un parametro della funzione anonima in modo che corrisponda al nome di una variabile locale, di una costante o di un parametro locale il cui ambito includa il anonymous_method_expression o 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.

Se una funzione anonima ha un explicit_anonymous_function_signature, il set di tipi delegati e tipi di albero delle espressioni compatibili è limitato a quelli che hanno gli stessi tipi di parametro e modificatori nello stesso ordine.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. Diversamente dalle conversioni di gruppi di metodi (conversioni di gruppi di metodi), la controvarianza dei tipi di parametro della funzione anonima non è supportata.In contrast to method group conversions (Method group conversions), contra-variance of anonymous function parameter types is not supported. Se una funzione anonima non dispone di un anonymous_function_signature, il set di tipi delegati e tipi di albero delle espressioni compatibili è limitato a quelli che non dispongono di parametri 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.

Si noti che un anonymous_function_signature non può includere attributi o una matrice di parametri.Note that an anonymous_function_signature cannot include attributes or a parameter array. Tuttavia, un anonymous_function_signature può essere compatibile con un tipo delegato il cui elenco di parametri contiene una matrice di parametri.Nevertheless, an anonymous_function_signature may be compatible with a delegate type whose parameter list contains a parameter array.

Si noti inoltre che la conversione in un tipo di albero delle espressioni, anche se compatibile, può ancora avere esito negativo in fase di compilazione (tipi di albero delle espressioni).Note also that conversion to an expression tree type, even if compatible, may still fail at compile-time (Expression tree types).

Corpi di funzioni anonimeAnonymous function bodies

Il corpo (espressione o blocco) di una funzione anonima è soggetto alle regole seguenti:The body (expression or block) of an anonymous function is subject to the following rules:

  • Se la funzione anonima include una firma, i parametri specificati nella firma sono disponibili nel corpo.If the anonymous function includes a signature, the parameters specified in the signature are available in the body. Se la funzione anonima non ha alcuna firma, può essere convertita in un tipo di delegato o di espressione con parametri (conversioni di funzioni anonime), ma non è possibile accedere ai parametri nel corpo.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.
  • Ad eccezione dei parametri ref o out specificati nella firma, se presente, della funzione anonima di inclusione più vicina, si tratta di un errore in fase di compilazione per il corpo per accedere a un parametro ref o out.Except for ref or out parameters specified in the signature (if any) of the nearest enclosing anonymous function, it is a compile-time error for the body to access a ref or out parameter.
  • Quando il tipo di this è un tipo struct, si tratta di un errore in fase di compilazione per il corpo per accedere this.When the type of this is a struct type, it is a compile-time error for the body to access this. Questo vale se l'accesso è esplicito (come in this.x) o implicito (come in x dove x è un membro di istanza dello struct).This is true whether the access is explicit (as in this.x) or implicit (as in x where x is an instance member of the struct). Questa regola impedisce semplicemente tale accesso e non influisce sull'eventuale risultato della ricerca dei membri in un membro dello struct.This rule simply prohibits such access and does not affect whether member lookup results in a member of the struct.
  • Il corpo ha accesso alle variabili esterne (variabili esterne) della funzione anonima.The body has access to the outer variables (Outer variables) of the anonymous function. L'accesso a una variabile esterna fa riferimento all'istanza della variabile attiva nel momento in cui viene valutata la lambda_expression o la anonymous_method_expression (valutazione di espressioni di funzione anonime).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).
  • Si tratta di un errore in fase di compilazione per il corpo che contiene un'istruzione goto, break istruzione o continue istruzione la cui destinazione è esterna al corpo o all'interno del corpo di una funzione anonima contenuta.It is a compile-time error for the body to contain a goto statement, break statement, or continue statement whose target is outside the body or within the body of a contained anonymous function.
  • Un'istruzione return nel corpo restituisce il controllo da una chiamata della funzione anonima di inclusione più vicina, non dal membro della funzione contenitore.A return statement in the body returns control from an invocation of the nearest enclosing anonymous function, not from the enclosing function member. Un'espressione specificata in un'istruzione return deve essere convertibile in modo implicito nel tipo restituito del tipo delegato o dell'albero delle espressioni in cui viene convertito il lambda_expression o il anonymous_method_expression di inclusione più vicino (conversioni di funzioni anonime).An expression specified in a return 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).

Non è specificato in modo esplicito se esiste un modo per eseguire il blocco di una funzione anonima diversa dalla valutazione e dalla chiamata del lambda_expression o 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 particolare, il compilatore può scegliere di implementare una funzione anonima sintetizzando uno o più metodi o tipi denominati.In particular, the compiler may choose to implement an anonymous function by synthesizing one or more named methods or types. I nomi di tali elementi sintetizzati devono essere di un modulo riservato per l'utilizzo da parte del compilatore.The names of any such synthesized elements must be of a form reserved for compiler use.

Risoluzione dell'overload e funzioni anonimeOverload resolution and anonymous functions

Le funzioni anonime in un elenco di argomenti partecipano all'inferenza del tipo e alla risoluzione dell'overload.Anonymous functions in an argument list participate in type inference and overload resolution. Per le regole esatte, vedere inferenza del tipo e risoluzione dell'overload .Please refer to Type inference and Overload resolution for the exact rules.

Nell'esempio seguente viene illustrato l'effetto delle funzioni anonime sulla risoluzione dell'overload.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;
    }
}

La classe ItemList<T> dispone di due metodi di Sum.The ItemList<T> class has two Sum methods. Ogni accetta un argomento selector, che estrae il valore da sommare da un elemento di elenco.Each takes a selector argument, which extracts the value to sum over from a list item. Il valore estratto può essere un int o un double e la somma risultante è analoga a un int o a una double.The extracted value can be either an int or a double and the resulting sum is likewise either an int or a double.

È possibile, ad esempio, usare i metodi Sum per calcolare somme da un elenco di righe di dettaglio in un ordine.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);
    ...
}

Nella prima chiamata di orderDetails.Sum, entrambi i metodi Sum sono applicabili perché la funzione anonima d => d. UnitCount è compatibile con Func<Detail,int> e 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>. Tuttavia, la risoluzione dell'overload sceglie il primo metodo di Sum perché la conversione in Func<Detail,int> è migliore rispetto alla conversione in 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>.

Nella seconda chiamata di orderDetails.Sum, viene applicato solo il secondo metodo Sum perché la funzione anonima d => d.UnitPrice * d.UnitCount produce un valore di tipo 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. Pertanto, la risoluzione dell'overload sceglie il secondo metodo Sum per la chiamata.Thus, overload resolution picks the second Sum method for that invocation.

Funzioni anonime e associazione dinamicaAnonymous functions and dynamic binding

Una funzione anonima non può essere un destinatario, un argomento o un operando di un'operazione associata dinamicamente.An anonymous function cannot be a receiver, argument or operand of a dynamically bound operation.

Variabili esterneOuter variables

Una variabile locale, un parametro di valore o una matrice di parametri il cui ambito include il lambda_expression o anonymous_method_expression è detta variabile esterna della funzione anonima.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. In un membro della funzione di istanza di una classe, il valore this viene considerato un parametro di valore ed è una variabile esterna di qualsiasi funzione anonima contenuta nel membro della funzione.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.

Variabili esterne acquisiteCaptured outer variables

Quando una funzione anonima fa riferimento a una variabile esterna, viene detto che la variabile esterna è stata acquisita dalla funzione anonima.When an outer variable is referenced by an anonymous function, the outer variable is said to have been captured by the anonymous function. In genere, la durata di una variabile locale è limitata all'esecuzione del blocco o dell'istruzione a cui è associata (variabili locali).Ordinarily, the lifetime of a local variable is limited to execution of the block or statement with which it is associated (Local variables). Tuttavia, la durata di una variabile esterna acquisita viene estesa almeno finché il delegato o l'albero delle espressioni creato dalla funzione anonima non diventa idoneo per Garbage Collection.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.

Nell'esempioIn 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());
    }
}

la variabile locale x viene acquisita dalla funzione anonima e la durata di x viene estesa almeno finché il delegato restituito da F diventa idoneo per Garbage Collection (che non si verifica fino alla fine del programma).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). Poiché ogni chiamata della funzione Anonymous opera sulla stessa istanza di x, l'output dell'esempio è:Since each invocation of the anonymous function operates on the same instance of x, the output of the example is:

1
2
3

Quando una variabile locale o un parametro di valore viene acquisito da una funzione anonima, la variabile o il parametro locale non è più considerato una variabile fissa (variabili fisse e mobili), ma è invece considerata una variabile mobile.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. Pertanto, qualsiasi codice unsafe che accetta l'indirizzo di una variabile esterna acquisita deve innanzitutto utilizzare l'istruzione fixed per correggere la variabile.Thus any unsafe code that takes the address of a captured outer variable must first use the fixed statement to fix the variable.

Si noti che a differenza di una variabile non acquisita, una variabile locale acquisita può essere esposta simultaneamente a più thread di esecuzione.Note that unlike an uncaptured variable, a captured local variable can be simultaneously exposed to multiple threads of execution.

Creazione di istanze di variabili localiInstantiation of local variables

Una variabile locale viene considerata come un'istanza quando l'esecuzione entra nell'ambito della variabile.A local variable is considered to be instantiated when execution enters the scope of the variable. Ad esempio, quando viene richiamato il metodo seguente, viene creata un'istanza della variabile locale x e inizializzata tre volte, una volta per ogni iterazione del ciclo.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;
        ...
    }
}

Tuttavia, lo spostato della dichiarazione di x all'esterno del ciclo comporta una singola creazione di istanza di 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;
        ...
    }
}

Quando non viene acquisita, non è possibile osservare esattamente la frequenza con cui viene creata un'istanza della variabile locale, perché la durata delle creazioni di istanze è disgiunta. è possibile che ogni creazione di istanza usi semplicemente lo stesso percorso di archiviazione.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. Tuttavia, quando una funzione anonima acquisisce una variabile locale, gli effetti della creazione di un'istanza diventano evidenti.However, when an anonymous function captures a local variable, the effects of instantiation become apparent.

EsempioThe 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();
    }
}

produce l'output:produces the output:

1
3
5

Tuttavia, quando la dichiarazione di x viene spostata all'esterno del ciclo: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;
}

si ottiene il seguente output:the output is:

5
5
5

Se un ciclo for dichiara una variabile di iterazione, la variabile stessa viene considerata dichiarata all'esterno del ciclo.If a for-loop declares an iteration variable, that variable itself is considered to be declared outside of the loop. Quindi, se l'esempio viene modificato per acquisire la variabile di iterazione stessa: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;
}

viene acquisita una sola istanza della variabile di iterazione che produce l'output:only one instance of the iteration variable is captured, which produces the output:

3
3
3

È possibile che i delegati di funzioni anonime possano condividere alcune variabili acquisite, ma hanno istanze separate di altri utenti.It is possible for anonymous function delegates to share some captured variables yet have separate instances of others. Ad esempio, se F viene modificato inFor 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;
}

i tre delegati acquisiscono la stessa istanza di x, ma le istanze separate di ye l'output è:the three delegates capture the same instance of x but separate instances of y, and the output is:

1 1
2 1
3 1

Funzioni anonime separate possono acquisire la stessa istanza di una variabile esterna.Separate anonymous functions can capture the same instance of an outer variable. Nell’esempioIn 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());
    }
}

le due funzioni anonime acquisiscono la stessa istanza della variabile locale xe possono quindi "comunicare" tramite tale variabile.the two anonymous functions capture the same instance of the local variable x, and they can thus "communicate" through that variable. L'output dell'esempio è:The output of the example is:

5
10

Valutazione di espressioni di funzione anonimeEvaluation of anonymous function expressions

Una funzione anonima F deve sempre essere convertita in un tipo di delegato D o un tipo di albero delle espressioni E, direttamente o tramite l'esecuzione di un'espressione di creazione del delegato 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). Questa conversione determina il risultato della funzione anonima, come descritto in conversioni di funzioni anonime.This conversion determines the result of the anonymous function, as described in Anonymous function conversions.

Espressioni di queryQuery expressions

Le espressioni di query forniscono una sintassi integrata del linguaggio per le query simili ai linguaggi di query relazionali e gerarchici, ad esempio SQL e 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
    ;

Un'espressione di query inizia con una clausola from e termina con una clausola select o group.A query expression begins with a from clause and ends with either a select or group clause. La clausola from iniziale può essere seguita da zero o più clausole from, let, where, join o orderby.The initial from clause can be followed by zero or more from, let, where, join or orderby clauses. Ogni clausola from è un generatore che introduce una variabile di intervallo che spazia sugli elementi di una sequenza.Each from clause is a generator introducing a range variable which ranges over the elements of a sequence. Ogni clausola let introduce una variabile di intervallo che rappresenta un valore calcolato per mezzo di variabili di intervallo precedenti.Each let clause introduces a range variable representing a value computed by means of previous range variables. Ogni clausola where è un filtro che esclude gli elementi dal risultato.Each where clause is a filter that excludes items from the result. Ogni clausola join Confronta le chiavi specificate della sequenza di origine con le chiavi di un'altra sequenza, ottenendo coppie corrispondenti.Each join clause compares specified keys of the source sequence with keys of another sequence, yielding matching pairs. Ogni clausola orderby Riordina gli elementi in base ai criteri specificati. La clausola select o group finale specifica la forma del risultato in termini di variabili di intervallo.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. Infine, è possibile usare una clausola into per "Splice" delle query trattando i risultati di una query come un generatore in una query successiva.Finally, an into clause can be used to "splice" queries by treating the results of one query as a generator in a subsequent query.

Ambiguità nelle espressioni di queryAmbiguities in query expressions

Le espressioni di query contengono un numero di "parole chiave contestuali", ovvero identificatori che hanno un significato speciale in un determinato contesto.Query expressions contain a number of "contextual keywords", i.e., identifiers that have special meaning in a given context. In particolare, si tratta di from, where, join, on, equals, into, let, orderby, ascending, descending, select, group e by.Specifically these are from, where, join, on, equals, into, let, orderby, ascending, descending, select, group and by. Per evitare ambiguità nelle espressioni di query causate dall'utilizzo misto di questi identificatori come parole chiave o nomi semplici, questi identificatori vengono considerati parole chiave quando si verificano in qualsiasi punto all'interno di un'espressione di query.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.

A tale scopo, un'espressione di query è qualsiasi espressione che inizia con "from identifier" seguito da un token ad eccezione di ";", "=" o ",".For this purpose, a query expression is any expression that starts with "from identifier" followed by any token except ";", "=" or ",".

Per usare queste parole come identificatori all'interno di un'espressione di query, è possibile che siano preceduti da "@" (identificatori).In order to use these words as identifiers within a query expression, they can be prefixed with "@" (Identifiers).

Conversione di espressioni di queryQuery expression translation

Il C# linguaggio non specifica la semantica di esecuzione delle espressioni di query.The C# language does not specify the execution semantics of query expressions. Piuttosto, le espressioni di query vengono convertite in chiamate di metodi che rispettano il modello di espressione di query (modello di espressione di query).Rather, query expressions are translated into invocations of methods that adhere to the query expression pattern (The query expression pattern). In particolare, le espressioni di query vengono convertite in chiamate di metodi denominati Where, Select, SelectMany, Join, GroupJoin, OrderBy, OrderByDescending, ThenBy, ThenByDescending, GroupBye Cast. Questi metodi dovrebbero avere firme e tipi di risultati specifici, come descritto nel modello di espressione di query.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. Questi metodi possono essere metodi di istanza dell'oggetto sottoposto a query o metodi di estensione esterni all'oggetto e implementano l'effettiva esecuzione della query.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.

La conversione dalle espressioni di query alle chiamate di metodo è un mapping sintattico che si verifica prima dell'esecuzione di qualsiasi associazione di tipo o risoluzione dell'overload.The translation from query expressions to method invocations is a syntactic mapping that occurs before any type binding or overload resolution has been performed. Si garantisce che la traduzione sia sintatticamente corretta, ma non è garantita la produzione di codice semanticamente corretto C# .The translation is guaranteed to be syntactically correct, but it is not guaranteed to produce semantically correct C# code. In seguito alla conversione di espressioni di query, le chiamate al metodo risultanti vengono elaborate come chiamate al metodo normali e ciò può a sua volta rivelare errori, ad esempio se i metodi non esistono, se gli argomenti presentano tipi errati o se i metodi sono generici e l'inferenza del tipo non riesce.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.

Un'espressione di query viene elaborata applicando ripetutamente le seguenti traduzioni fino a quando non sono possibili ulteriori riduzioni.A query expression is processed by repeatedly applying the following translations until no further reductions are possible. Le traduzioni sono elencate in ordine di applicazione: ogni sezione presuppone che le traduzioni nelle sezioni precedenti siano state eseguite in modo esaustivo e, una volta esaurita, una sezione non verrà rivisitata in un secondo momento nell'elaborazione della stessa espressione di query.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.

L'assegnazione a variabili di intervallo non è consentita nelle espressioni di query.Assignment to range variables is not allowed in query expressions. Tuttavia, C# un'implementazione è autorizzata a non sempre applicare questa restrizione, perché questo potrebbe talvolta non essere possibile con lo schema di conversione sintattico presentato qui.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.

Alcune traduzioni inseriscono variabili di intervallo con identificatori trasparenti identificati da *.Certain translations inject range variables with transparent identifiers denoted by *. Le proprietà speciali degli identificatori trasparenti sono illustrate ulteriormente negli identificatori trasparenti.The special properties of transparent identifiers are discussed further in Transparent identifiers.

Clausole SELECT e GroupBy con continuazioniSelect and groupby clauses with continuations

Espressione di query con una continuazioneA query expression with a continuation

from ... into x ...

viene convertito inis translated into

from x in ( from ... ) ...

Le traduzioni nelle sezioni seguenti presuppongono che le query non includano continuazioni into.The translations in the following sections assume that queries have no into continuations.

EsempioThe example

from c in customers
group c by c.Country into g
select new { Country = g.Key, CustCount = g.Count() }

viene convertito inis translated into

from g in
    from c in customers
    group c by c.Country
select new { Country = g.Key, CustCount = g.Count() }

la traduzione finale dithe final translation of which is

customers.
GroupBy(c => c.Country).
Select(g => new { Country = g.Key, CustCount = g.Count() })

Tipi di variabili di intervallo espliciteExplicit range variable types

Clausola from che specifica in modo esplicito un tipo di variabile di intervalloA from clause that explicitly specifies a range variable type

from T x in e

viene convertito inis translated into

from x in ( e ) . Cast < T > ( )

Clausola join che specifica in modo esplicito un tipo di variabile di intervalloA join clause that explicitly specifies a range variable type

join T x in e on k1 equals k2

viene convertito inis translated into

join x in ( e ) . Cast < T > ( ) on k1 equals k2

Le traduzioni nelle sezioni seguenti presuppongono che le query non includano tipi di variabile di intervallo espliciti.The translations in the following sections assume that queries have no explicit range variable types.

EsempioThe example

from Customer c in customers
where c.City == "London"
select c

viene convertito inis translated into

from c in customers.Cast<Customer>()
where c.City == "London"
select c

la traduzione finale dithe final translation of which is

customers.
Cast<Customer>().
Where(c => c.City == "London")

I tipi di variabile di intervallo espliciti sono utili per eseguire query su raccolte che implementano l'interfaccia non generica IEnumerable, ma non l'interfaccia di IEnumerable<T> generica.Explicit range variable types are useful for querying collections that implement the non-generic IEnumerable interface, but not the generic IEnumerable<T> interface. Nell'esempio precedente, questo sarebbe il caso customers fossero di tipo ArrayList.In the example above, this would be the case if customers were of type ArrayList.

Degenerare espressioni di queryDegenerate query expressions

Espressione di query nel formatoA query expression of the form

from x in e select x

viene convertito inis translated into

( e ) . Select ( x => x )

EsempioThe example

from c in customers
select c

viene convertito inis translated into

customers.Select(c => c)

Un'espressione di query degenere consente di selezionare in modo banale gli elementi dell'origine.A degenerate query expression is one that trivially selects the elements of the source. Una fase successiva della traduzione rimuove le query degenerate introdotte da altri passaggi di traduzione sostituendolo con l'origine.A later phase of the translation removes degenerate queries introduced by other translation steps by replacing them with their source. È tuttavia importante verificare che il risultato di un'espressione di query non sia mai l'oggetto di origine, in quanto ciò potrebbe rivelare il tipo e l'identità del codice sorgente al client della query.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. Pertanto, questo passaggio protegge le query degenerate scritte direttamente nel codice sorgente chiamando in modo esplicito Select nell'origine.Therefore this step protects degenerate queries written directly in source code by explicitly calling Select on the source. Per assicurarsi che questi metodi non restituiscano mai l'oggetto di origine, i responsabili dell'implementazione di Select e di altri operatori di query.It is then up to the implementers of Select and other query operators to ensure that these methods never return the source object itself.

Clausole from, Let, where, join e OrderByFrom, let, where, join and orderby clauses

Espressione di query con una seconda clausola from seguita da una clausola selectA query expression with a second from clause followed by a select clause

from x1 in e1
from x2 in e2
select v

viene convertito inis translated into

( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => v )

Un'espressione di query con una seconda clausola from seguita da un elemento diverso da una clausola 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
...

viene convertito inis translated into

from * in ( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => new { x1 , x2 } )
...

Espressione di query con una clausola letA query expression with a let clause

from x in e
let y = f
...

viene convertito inis translated into

from * in ( e ) . Select ( x => new { x , y = f } )
...

Espressione di query con una clausola whereA query expression with a where clause

from x in e
where f
...

viene convertito inis translated into

from x in ( e ) . Where ( x => f )
...

Espressione di query con una clausola join senza un into seguito da una clausola selectA 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

viene convertito inis translated into

( e1 ) . Join( e2 , x1 => k1 , x2 => k2 , ( x1 , x2 ) => v )

Espressione di query con una clausola join senza un into seguito da un elemento diverso da una clausola selectA 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
...

viene convertito inis translated into

from * in ( e1 ) . Join( e2 , x1 => k1 , x2 => k2 , ( x1 , x2 ) => new { x1 , x2 })
...

Espressione di query con una clausola join con un into seguito da una clausola selectA 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

viene convertito inis translated into

( e1 ) . GroupJoin( e2 , x1 => k1 , x2 => k2 , ( x1 , g ) => v )

Espressione di query con una clausola join con un into seguito da un elemento diverso da una clausola selectA 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
...

viene convertito inis translated into

from * in ( e1 ) . GroupJoin( e2 , x1 => k1 , x2 => k2 , ( x1 , g ) => new { x1 , g })
...

Espressione di query con una clausola orderbyA query expression with an orderby clause

from x in e
orderby k1 , k2 , ..., kn
...

viene convertito inis translated into

from x in ( e ) . 
OrderBy ( x => k1 ) . 
ThenBy ( x => k2 ) .
... .
ThenBy ( x => kn )
...

Se una clausola di ordinamento specifica un indicatore di direzione di descending, viene invece prodotta una chiamata di OrderByDescending o ThenByDescending.If an ordering clause specifies a descending direction indicator, an invocation of OrderByDescending or ThenByDescending is produced instead.

Nelle traduzioni seguenti si presuppone che non esistano clausole let, where, join o orderby e non più di una clausola di from iniziale in ogni espressione di query.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.

EsempioThe example

from c in customers
from o in c.Orders
select new { c.Name, o.OrderID, o.Total }

viene convertito inis translated into

customers.
SelectMany(c => c.Orders,
     (c,o) => new { c.Name, o.OrderID, o.Total }
)

EsempioThe example

from c in customers
from o in c.Orders
orderby o.Total descending
select new { c.Name, o.OrderID, o.Total }

viene convertito inis 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 }

la traduzione finale dithe 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 })

dove x è un identificatore generato dal compilatore che altrimenti è invisibile e inaccessibile.where x is a compiler generated identifier that is otherwise invisible and inaccessible.

EsempioThe example

from o in orders
let t = o.Details.Sum(d => d.UnitPrice * d.Quantity)
where t >= 1000
select new { o.OrderID, Total = t }

viene convertito inis 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 }

la traduzione finale dithe 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 })

dove x è un identificatore generato dal compilatore che altrimenti è invisibile e inaccessibile.where x is a compiler generated identifier that is otherwise invisible and inaccessible.

EsempioThe example

from c in customers
join o in orders on c.CustomerID equals o.CustomerID
select new { c.Name, o.OrderDate, o.Total }

viene convertito inis translated into

customers.Join(orders, c => c.CustomerID, o => o.CustomerID,
    (c, o) => new { c.Name, o.OrderDate, o.Total })

EsempioThe 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 }

viene convertito inis 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 }

la traduzione finale dithe 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)

dove x e y sono identificatori generati dal compilatore che altrimenti sono invisibili e inaccessibili.where x and y are compiler generated identifiers that are otherwise invisible and inaccessible.

EsempioThe example

from o in orders
orderby o.Customer.Name, o.Total descending
select o

ha la traduzione finalehas the final translation

orders.
OrderBy(o => o.Customer.Name).
ThenByDescending(o => o.Total)

Clausola SELECTSelect clauses

Espressione di query nel formatoA query expression of the form

from x in e select v

viene convertito inis translated into

( e ) . Select ( x => v )

eccetto quando v è l'identificatore x, la traduzione è semplicementeexcept when v is the identifier x, the translation is simply

( e )

Esempio:For example

from c in customers.Where(c => c.City == "London")
select c

viene semplicemente convertito inis simply translated into

customers.Where(c => c.City == "London")

Clausole GroupByGroupby clauses

Espressione di query nel formatoA query expression of the form

from x in e group v by k

viene convertito inis translated into

( e ) . GroupBy ( x => k , x => v )

eccetto quando v è l'identificatore x, la traduzione èexcept when v is the identifier x, the translation is

( e ) . GroupBy ( x => k )

EsempioThe example

from c in customers
group c.Name by c.Country

viene convertito inis translated into

customers.
GroupBy(c => c.Country, c => c.Name)

Identificatori trasparentiTransparent identifiers

Alcune traduzioni inseriscono variabili di intervallo con identificatori trasparenti identificati da *.Certain translations inject range variables with transparent identifiers denoted by *. Gli identificatori trasparenti non sono una funzionalità del linguaggio corretta. esistono solo come un passaggio intermedio nel processo di conversione delle espressioni di query.Transparent identifiers are not a proper language feature; they exist only as an intermediate step in the query expression translation process.

Quando una conversione di query inserisce un identificatore trasparente, ulteriori passaggi di conversione propagano l'identificatore trasparente in funzioni anonime e inizializzatori di oggetti anonimi.When a query translation injects a transparent identifier, further translation steps propagate the transparent identifier into anonymous functions and anonymous object initializers. In questi contesti gli identificatori trasparenti hanno il seguente comportamento:In those contexts, transparent identifiers have the following behavior:

  • Quando si verifica un identificatore trasparente come parametro in una funzione anonima, i membri del tipo anonimo associato vengono automaticamente inclusi nell'ambito nel corpo della funzione anonima.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.
  • Quando un membro con un identificatore transparent è nell'ambito, anche i membri di tale membro sono inclusi nell'ambito.When a member with a transparent identifier is in scope, the members of that member are in scope as well.
  • Quando un identificatore trasparente si verifica come un dichiaratore di membro in un inizializzatore di oggetto anonimo, introduce un membro con un identificatore Transparent.When a transparent identifier occurs as a member declarator in an anonymous object initializer, it introduces a member with a transparent identifier.
  • Nei passaggi di traduzione descritti in precedenza, gli identificatori trasparenti vengono sempre introdotti insieme ai tipi anonimi, con lo scopo di acquisire più variabili di intervallo come membri di un singolo oggetto.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. Un'implementazione di C# è autorizzata a usare un meccanismo diverso rispetto ai tipi anonimi per raggruppare più variabili di intervallo.An implementation of C# is permitted to use a different mechanism than anonymous types to group together multiple range variables. Negli esempi di traduzione seguenti si presuppone che vengano utilizzati i tipi anonimi e viene illustrato il modo in cui gli identificatori trasparenti possono essere convertiti.The following translation examples assume that anonymous types are used, and show how transparent identifiers can be translated away.

EsempioThe example

from c in customers
from o in c.Orders
orderby o.Total descending
select new { c.Name, o.Total }

viene convertito inis translated into

from * in customers.
    SelectMany(c => c.Orders, (c,o) => new { c, o })
orderby o.Total descending
select new { c.Name, o.Total }

che viene ulteriormente tradotta inwhich is further translated into

customers.
SelectMany(c => c.Orders, (c,o) => new { c, o }).
OrderByDescending(* => o.Total).
Select(* => new { c.Name, o.Total })

che, quando gli identificatori trasparenti vengono cancellati, è equivalente awhich, 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 })

dove x è un identificatore generato dal compilatore che altrimenti è invisibile e inaccessibile.where x is a compiler generated identifier that is otherwise invisible and inaccessible.

EsempioThe 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 }

viene convertito inis 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 }

che è ulteriormente ridotto awhich 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 })

la traduzione finale dithe 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 })

dove x, ye z sono identificatori generati dal compilatore che altrimenti sono invisibili e inaccessibili.where x, y, and z are compiler generated identifiers that are otherwise invisible and inaccessible.

Modello di espressione di queryThe query expression pattern

Il modello di espressione di query stabilisce un modello di metodi che i tipi possono implementare per supportare le espressioni di query.The Query expression pattern establishes a pattern of methods that types can implement to support query expressions. Poiché le espressioni di query vengono convertite in chiamate ai metodi mediante un mapping sintattico, i tipi hanno una notevole flessibilità nel modo in cui implementano il modello di espressione di query.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. Ad esempio, i metodi del modello possono essere implementati come metodi di istanza o come metodi di estensione perché i due hanno la stessa sintassi di chiamata e i metodi possono richiedere delegati o alberi delle espressioni perché le funzioni anonime sono convertibili in entrambi.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.

La forma consigliata di un tipo generico C<T> che supporta il modello di espressione di query è illustrata di seguito.The recommended shape of a generic type C<T> that supports the query expression pattern is shown below. Un tipo generico viene usato per illustrare le relazioni appropriate tra i tipi di parametro e di risultato, ma è possibile implementare il modello anche per i tipi non generici.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; }
}

I metodi precedenti usano i tipi delegati generici Func<T1,R> e Func<T1,T2,R>, ma potrebbero avere ugualmente usato altri tipi di albero delle espressioni o di delegato con le stesse relazioni nei tipi di parametro e di risultato.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.

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.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. Also notice the recommended shape of the result of GroupBy -- a sequence of sequences, where each inner sequence has an additional Key property.Also notice the recommended shape of the result of GroupBy -- a sequence of sequences, where each inner sequence has an additional Key property.

The System.Linq namespace provides an implementation of the query operator pattern for any type that implements the System.Collections.Generic.IEnumerable<T> interface.The System.Linq namespace provides an implementation of the query operator pattern for any type that implements the System.Collections.Generic.IEnumerable<T> interface.

Operatori di assegnazioneAssignment operators

The assignment operators assign a new value to a variable, a property, an event, or an indexer element.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 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.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.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 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 simple assignment operator is described in Simple assignment.

The assignment operators other than the = operator are called the compound assignment operators.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.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 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.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.No other assignment operator is valid with an event access as the left operand. The event assignment operators are described in Event assignment.The event assignment operators are described in Event assignment.

The assignment operators are right-associative, meaning that operations are grouped from right to left.The assignment operators are right-associative, meaning that operations are grouped from right to left. For example, an expression of the form a = b = c is evaluated as a = (b = c).For example, an expression of the form a = b = c is evaluated as a = (b = c).

Assegnazione singolaSimple assignment

The = operator is called the simple assignment operator.The = operator is called the simple assignment operator.

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).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). In questo caso il tipo in fase di compilazione dell'espressione di assegnazione è dynamice la risoluzione descritta di seguito verrà eseguita in fase di esecuzione in base al tipo di runtime di 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.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 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 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.The result has the same type as the left operand and is always classified as a value.

If the left operand is a property or indexer access, the property or indexer must have a set accessor.If the left operand is a property or indexer access, the property or indexer must have a set accessor. In caso contrario, si verificherà un errore in fase di binding.If this is not the case, a binding-time error occurs.

The run-time processing of a simple assignment of the form x = y consists of the following steps:The run-time processing of a simple assignment of the form x = y consists of the following steps:

  • If x is classified as a variable:If x is classified as a variable:
    • x is evaluated to produce the variable.x is evaluated to produce the variable.
    • y viene valutata e, se necessario, convertita nel tipo di x tramite una conversione implicita (conversioni implicite).y is evaluated and, if required, converted to the type of x through an implicit conversion (Implicit conversions).
    • Se la variabile fornita da x è un elemento di matrice di una reference_type, viene eseguito un controllo di runtime per garantire che il valore calcolato per y sia compatibile con l'istanza di matrice di cui x è un elemento.If the variable given by x is an array element of a reference_type, a run-time check is performed to ensure that the value computed for y is compatible with the array instance of which x is an element. Il controllo ha esito positivo se y viene nullo se esiste una conversione implicita dei riferimenti (conversioni di riferimenti impliciti) dal tipo effettivo dell'istanza a cui fa riferimento y al tipo di elemento effettivo dell'istanza di matrice che contiene x.The check succeeds if y is null, or if an implicit reference conversion (Implicit reference conversions) exists from the actual type of the instance referenced by y to the actual element type of the array instance containing x. In caso contrario viene generata un'eccezione System.ArrayTypeMismatchException.Otherwise, a System.ArrayTypeMismatchException is thrown.
    • Il valore risultante dalla valutazione e dalla conversione di y viene archiviato nella posizione specificata dalla valutazione di x.The value resulting from the evaluation and conversion of y is stored into the location given by the evaluation of x.
  • Se x è classificato come accesso a una proprietà o a un indicizzatore:If x is classified as a property or indexer access:
    • L'espressione dell'istanza (se x non è static) e l'elenco di argomenti (se x è un accesso all'indicizzatore) associato a x vengono valutati e i risultati vengono usati nella chiamata della funzione di accesso set successiva.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 set accessor invocation.
    • y viene valutata e, se necessario, convertita nel tipo di x tramite una conversione implicita (conversioni implicite).y is evaluated and, if required, converted to the type of x through an implicit conversion (Implicit conversions).
    • Viene richiamata la funzione di accesso set di x con il valore calcolato per y come argomento value.The set accessor of x is invoked with the value computed for y as its value argument.

Le regole di covarianza della matrice (covarianza di matrice) consentono un valore di un tipo di matrice A[] essere un riferimento a un'istanza di un tipo di matrice B[], purché esista una conversione implicita del riferimento da B a 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. A causa di queste regole, l'assegnazione a un elemento di matrice di una reference_type richiede un controllo Runtime per garantire che il valore assegnato sia compatibile con l'istanza di matrice.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. Nell'esempioIn the example

string[] sa = new string[10];
object[] oa = sa;

oa[0] = null;               // Ok
oa[1] = "Hello";            // Ok
oa[2] = new ArrayList();    // ArrayTypeMismatchException

L'ultima assegnazione causa la generazione di un System.ArrayTypeMismatchException perché un'istanza di ArrayList non può essere archiviata in un elemento di un 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[].

Quando una proprietà o un indicizzatore dichiarato in una struct_type è la destinazione di un'assegnazione, l'espressione dell'istanza associata alla proprietà o all'indicizzatore deve essere classificata come variabile.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. Se l'espressione dell'istanza è classificata come valore, si verifica un errore in fase di binding.If the instance expression is classified as a value, a binding-time error occurs. A causa dell' accesso ai membri, la stessa regola si applica anche ai campi.Because of Member access, the same rule also applies to fields.

Date le dichiarazioni: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; }
    }
}

Nell'esempioin 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;

sono consentite le assegnazioni di p.X, p.Y, r.Ae r.B perché p e r sono variabili.the assignments to p.X, p.Y, r.A, and r.B are permitted because p and r are variables. Tuttavia, nell'esempioHowever, in the example

Rectangle r = new Rectangle();
r.A.X = 10;
r.A.Y = 10;
r.B.X = 100;
r.B.Y = 100;

tutte le assegnazioni non sono valide perché r.A e r.B non sono variabili.the assignments are all invalid, since r.A and r.B are not variables.

Assegnazione compostaCompound assignment

Se l'operando sinistro di un'assegnazione composta è nel formato E.P o E[Ei] dove E ha il tipo in fase di compilazione dynamic, l'assegnazione viene associata dinamicamente (associazione dinamica).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). In questo caso il tipo in fase di compilazione dell'espressione di assegnazione è dynamice la risoluzione descritta di seguito verrà eseguita in fase di esecuzione in base al tipo di runtime di 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.

Un'operazione del modulo x op= y viene elaborata applicando la risoluzione dell'overload dell'operatore binario (risoluzione dell'overload dell'operatore binario) come se l'operazione fosse stata scritta 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. Con questi presupposti,Then,

  • Se il tipo restituito dell'operatore selezionato è convertibile in modo implicito nel tipo di x, l'operazione viene valutata come x = x op y, ad eccezione del fatto che x viene valutato una sola volta.If the return type of the selected operator is implicitly convertible to the type of x, the operation is evaluated as x = x op y, except that x is evaluated only once.
  • In caso contrario, se l'operatore selezionato è un operatore predefinito, se il tipo restituito dell'operatore selezionato è convertibile in modo esplicito nel tipo di xe se y è convertibile in modo implicito nel tipo di x o se l'operatore è un operatore Shift, l'operazione viene valutata come x = (T)(x op y), dove T è il tipo di x, con la differenza che x viene valutato una sola voltaOtherwise, if the selected operator is a predefined operator, if the return type of the selected operator is explicitly convertible to the type of x, and if y is implicitly convertible to the type of x or the operator is a shift operator, then the operation is evaluated as x = (T)(x op y), where T is the type of x, except that x is evaluated only once.
  • In caso contrario, l'assegnazione composta non è valida e si verifica un errore in fase di binding.Otherwise, the compound assignment is invalid, and a binding-time error occurs.

Il termine "valutato una sola volta" significa che nella valutazione di x op y, i risultati di qualsiasi espressione costituente di x vengono salvati temporaneamente e quindi riusati quando si esegue l'assegnazione a 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. Ad esempio, nel A()[B()] += C()di assegnazione, dove A è un metodo che restituisce int[]e B e C sono metodi che restituiscono int, i metodi vengono richiamati una sola volta, nell'ordine 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.

Quando l'operando sinistro di un'assegnazione composta è un accesso a una proprietà o un indicizzatore, la proprietà o l'indicizzatore deve avere sia una funzione di accesso get che una funzione di accesso 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. In caso contrario, si verificherà un errore in fase di binding.If this is not the case, a binding-time error occurs.

La seconda regola precedente consente di valutare x op= y come x = (T)(x op y) in determinati contesti.The second rule above permits x op= y to be evaluated as x = (T)(x op y) in certain contexts. La regola esiste in modo tale che gli operatori predefiniti possono essere utilizzati come operatori composti quando l'operando sinistro è di tipo sbyte, byte, short, ushorto 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. Anche quando entrambi gli argomenti sono di uno di questi tipi, gli operatori predefiniti producono un risultato di tipo int, come descritto in Promotion numeric Binary.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. Senza un cast, quindi, non sarebbe possibile assegnare il risultato all'operando sinistro.Thus, without a cast it would not be possible to assign the result to the left operand.

L'effetto intuitivo della regola per gli operatori predefiniti è semplicemente che x op= y è consentito se sono consentiti sia x op y che 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. Nell'esempioIn 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

il motivo intuitivo di ogni errore è che anche un'assegnazione semplice corrispondente potrebbe essere un errore.the intuitive reason for each error is that a corresponding simple assignment would also have been an error.

Ciò significa anche che le operazioni di assegnazione composta supportano le operazioni lifted.This also means that compound assignment operations support lifted operations. Nell'esempioIn the example

int? i = 0;
i += 1;             // Ok

viene usato l'operatore lifted +(int?,int?).the lifted operator +(int?,int?) is used.

Assegnazione eventoEvent assignment

Se l'operando sinistro di un operatore += o -= è classificato come accesso a un evento, l'espressione viene valutata nel modo seguente:If the left operand of a += or -= operator is classified as an event access, then the expression is evaluated as follows:

  • L'espressione dell'istanza, se presente, dell'accesso agli eventi viene valutata.The instance expression, if any, of the event access is evaluated.
  • Viene valutato l'operando destro dell'operatore += o -= e, se necessario, viene convertito nel tipo dell'operando sinistro tramite una conversione implicita (conversioni implicite).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).
  • Viene richiamata una funzione di accesso eventi dell'evento, con elenco di argomenti costituito dall'operando di destra, dopo la valutazione e, se necessario, la conversione.An event accessor of the event is invoked, with argument list consisting of the right operand, after evaluation and, if necessary, conversion. Se l'operatore è stato +=, viene richiamata la funzione di accesso add; Se l'operatore è stato -=, viene richiamata la funzione di accesso remove.If the operator was +=, the add accessor is invoked; if the operator was -=, the remove accessor is invoked.

Un'espressione di assegnazione di evento non restituisce alcun valore.An event assignment expression does not yield a value. Pertanto, un'espressione di assegnazione eventi è valida solo nel contesto di un statement_expression (istruzioni Expression).Thus, an event assignment expression is valid only in the context of a statement_expression (Expression statements).

EspressioneExpression

Un' espressione può essere una non_assignment_expression o un' assegnazione.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
    ;

Espressioni costantiConstant expressions

Un constant_expression è un'espressione che può essere valutata interamente in fase di compilazione.A constant_expression is an expression that can be fully evaluated at compile-time.

constant_expression
    : expression
    ;

Un'espressione costante deve essere il valore letterale null o un valore con uno dei tipi seguenti: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, object, stringo qualsiasi tipo di enumerazione.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. Nelle espressioni costanti sono consentiti solo i costrutti seguenti:Only the following constructs are permitted in constant expressions:

  • Valori letterali (inclusa la null valore letterale).Literals (including the null literal).
  • Riferimenti a const membri dei tipi di classe e struct.References to const members of class and struct types.
  • Riferimenti a membri di tipi di enumerazione.References to members of enumeration types.
  • Riferimenti a parametri const o variabili localiReferences to const