InstruccionesStatements
C# proporciona diversas instrucciones.C# provides a variety of statements. La mayoría de estas instrucciones serán familiares para los desarrolladores que han programado en C y C++.Most of these statements will be familiar to developers who have programmed in C and C++.
statement
: labeled_statement
| declaration_statement
| embedded_statement
;
embedded_statement
: block
| empty_statement
| expression_statement
| selection_statement
| iteration_statement
| jump_statement
| try_statement
| checked_statement
| unchecked_statement
| lock_statement
| using_statement
| yield_statement
| embedded_statement_unsafe
;
El embedded_statement nonterminal se utiliza para las instrucciones que aparecen dentro de otras instrucciones.The embedded_statement nonterminal is used for statements that appear within other statements. El uso de embedded_statement en lugar de Statement excluye el uso de las instrucciones de declaración y las instrucciones con etiquetas en estos contextos.The use of embedded_statement rather than statement excludes the use of declaration statements and labeled statements in these contexts. En el ejemploThe example
void F(bool b) {
if (b)
int i = 44;
}
genera un error en tiempo de compilación porque una if
instrucción requiere una embedded_statement en lugar de una instrucción para su bifurcación if.results in a compile-time error because an if
statement requires an embedded_statement rather than a statement for its if branch. Si se permitía este código, la variable i
se declararía, pero nunca se podía usar.If this code were permitted, then the variable i
would be declared, but it could never be used. Tenga en cuenta, sin embargo, que si coloca i
la declaración de en un bloque, el ejemplo es válido.Note, however, that by placing i
's declaration in a block, the example is valid.
Puntos finales y alcanceEnd points and reachability
Cada instrucción tiene un punto final.Every statement has an end point. En términos intuitivos, el punto final de una instrucción es la ubicación que sigue inmediatamente a la instrucción.In intuitive terms, the end point of a statement is the location that immediately follows the statement. Las reglas de ejecución para las instrucciones compuestas (instrucciones que contienen instrucciones incrustadas) especifican la acción que se realiza cuando el control alcanza el punto final de una instrucción incrustada.The execution rules for composite statements (statements that contain embedded statements) specify the action that is taken when control reaches the end point of an embedded statement. Por ejemplo, cuando el control alcanza el punto final de una instrucción en un bloque, el control se transfiere a la siguiente instrucción del bloque.For example, when control reaches the end point of a statement in a block, control is transferred to the next statement in the block.
Si la ejecución puede alcanzar una instrucción, se dice que la instrucción es *accesible _.If a statement can possibly be reached by execution, the statement is said to be *reachable _. Por el contrario, si no hay ninguna posibilidad de que se ejecute una instrucción, se dice que la instrucción es _ inaccesible *.Conversely, if there is no possibility that a statement will be executed, the statement is said to be _*unreachable**.
En el ejemploIn the example
void F() {
Console.WriteLine("reachable");
goto Label;
Console.WriteLine("unreachable");
Label:
Console.WriteLine("reachable");
}
la segunda invocación de Console.WriteLine
es inaccesible porque no existe ninguna posibilidad de que se ejecute la instrucción.the second invocation of Console.WriteLine
is unreachable because there is no possibility that the statement will be executed.
Se genera una advertencia si el compilador determina que no se puede tener acceso a una instrucción.A warning is reported if the compiler determines that a statement is unreachable. No se trata de un error específico para que no se pueda tener acceso a una instrucción.It is specifically not an error for a statement to be unreachable.
Para determinar si una instrucción o un extremo concreto es accesible, el compilador realiza el análisis de flujo según las reglas de disponibilidad definidas para cada instrucción.To determine whether a particular statement or end point is reachable, the compiler performs flow analysis according to the reachability rules defined for each statement. El análisis de flujo tiene en cuenta los valores de expresiones constantes (expresiones constantes) que controlan el comportamiento de las instrucciones, pero no se tienen en cuenta los valores posibles de las expresiones que no son constantes.The flow analysis takes into account the values of constant expressions (Constant expressions) that control the behavior of statements, but the possible values of non-constant expressions are not considered. En otras palabras, a efectos del análisis de flujo de control, se considera que una expresión no constante de un tipo determinado tiene cualquier valor posible de ese tipo.In other words, for purposes of control flow analysis, a non-constant expression of a given type is considered to have any possible value of that type.
En el ejemploIn the example
void F() {
const int i = 1;
if (i == 2) Console.WriteLine("unreachable");
}
la expresión booleana de la if
instrucción es una expresión constante porque ambos operandos del ==
operador son constantes.the boolean expression of the if
statement is a constant expression because both operands of the ==
operator are constants. Como la expresión constante se evalúa en tiempo de compilación, lo que genera el valor false
, Console.WriteLine
se considera que la invocación no es accesible.As the constant expression is evaluated at compile-time, producing the value false
, the Console.WriteLine
invocation is considered unreachable. Sin embargo, si i
se cambia para ser una variable localHowever, if i
is changed to be a local variable
void F() {
int i = 1;
if (i == 2) Console.WriteLine("reachable");
}
la Console.WriteLine
invocación se considera accesible, aunque, en realidad, nunca se ejecutará.the Console.WriteLine
invocation is considered reachable, even though, in reality, it will never be executed.
El bloque de un miembro de función siempre se considera alcanzable.The block of a function member is always considered reachable. Al evaluar sucesivamente las reglas de disponibilidad de cada instrucción en un bloque, se puede determinar la disponibilidad de cualquier instrucción determinada.By successively evaluating the reachability rules of each statement in a block, the reachability of any given statement can be determined.
En el ejemploIn the example
void F(int x) {
Console.WriteLine("start");
if (x < 0) Console.WriteLine("negative");
}
la disponibilidad de la segunda Console.WriteLine
se determina de la siguiente manera:the reachability of the second Console.WriteLine
is determined as follows:
- La primera
Console.WriteLine
instrucción de expresión es accesible porque el bloque delF
método es accesible.The firstConsole.WriteLine
expression statement is reachable because the block of theF
method is reachable. - El punto final de la primera
Console.WriteLine
instrucción de expresión es accesible porque esa instrucción es accesible.The end point of the firstConsole.WriteLine
expression statement is reachable because that statement is reachable. - La
if
instrucción es accesible porque el punto final de la primeraConsole.WriteLine
instrucción de expresión es accesible.Theif
statement is reachable because the end point of the firstConsole.WriteLine
expression statement is reachable. - La segunda
Console.WriteLine
instrucción de expresión es accesible porque la expresión booleana de laif
instrucción no tiene el valor constantefalse
.The secondConsole.WriteLine
expression statement is reachable because the boolean expression of theif
statement does not have the constant valuefalse
.
Hay dos situaciones en las que se trata de un error en tiempo de compilación para que el punto final de una instrucción sea alcanzable:There are two situations in which it is a compile-time error for the end point of a statement to be reachable:
- Dado que la
switch
instrucción no permite que una sección switch pase a la siguiente sección switch, se trata de un error en tiempo de compilación para que el punto final de la lista de instrucciones de una sección switch sea accesible.Because theswitch
statement does not permit a switch section to "fall through" to the next switch section, it is a compile-time error for the end point of the statement list of a switch section to be reachable. Si se produce este error, normalmente es una indicación de quebreak
falta una instrucción.If this error occurs, it is typically an indication that abreak
statement is missing. - Es un error en tiempo de compilación el punto final del bloque de un miembro de función que calcula un valor al que se puede tener acceso.It is a compile-time error for the end point of the block of a function member that computes a value to be reachable. Si se produce este error, normalmente es una indicación de que
return
falta una instrucción.If this error occurs, it typically is an indication that areturn
statement is missing.
BlocksBlocks
Un bloque permite que se escriban varias instrucciones en contextos donde se permite una única instrucción.A block permits multiple statements to be written in contexts where a single statement is allowed.
block
: '{' statement_list? '}'
;
Un bloque consta de un statement_list opcional (listas de instrucciones), entre llaves.A block consists of an optional statement_list (Statement lists), enclosed in braces. Si se omite la lista de instrucciones, se dice que el bloque está vacío.If the statement list is omitted, the block is said to be empty.
Un bloque puede contener instrucciones de declaración (instrucciones de declaración).A block may contain declaration statements (Declaration statements). El ámbito de una variable local o constante declarada en un bloque es el bloque.The scope of a local variable or constant declared in a block is the block.
Un bloque se ejecuta de la siguiente manera:A block is executed as follows:
- Si el bloque está vacío, el control se transfiere al punto final del bloque.If the block is empty, control is transferred to the end point of the block.
- Si el bloque no está vacío, el control se transfiere a la lista de instrucciones.If the block is not empty, control is transferred to the statement list. Cuando y si el control alcanza el punto final de la lista de instrucciones, el control se transfiere al punto final del bloque.When and if control reaches the end point of the statement list, control is transferred to the end point of the block.
La lista de instrucciones de un bloque es accesible si el propio bloque es accesible.The statement list of a block is reachable if the block itself is reachable.
El punto final de un bloque es accesible si el bloque está vacío o si el punto final de la lista de instrucciones es accesible.The end point of a block is reachable if the block is empty or if the end point of the statement list is reachable.
Un bloque que contiene una o más yield
instrucciones (la instrucción yield) se denomina bloque de iteradores.A block that contains one or more yield
statements (The yield statement) is called an iterator block. Los bloques de iterador se usan para implementar miembros de función como iteradores (iteradores).Iterator blocks are used to implement function members as iterators (Iterators). Se aplican algunas restricciones adicionales a los bloques de iteradores:Some additional restrictions apply to iterator blocks:
- Se trata de un error en tiempo de compilación para
return
que una instrucción aparezca en un bloque de iteradores (peroyield return
se permiten las instrucciones).It is a compile-time error for areturn
statement to appear in an iterator block (butyield return
statements are permitted). - Es un error en tiempo de compilación que un bloque de iteradores contenga un contexto no seguro (contextos no seguros).It is a compile-time error for an iterator block to contain an unsafe context (Unsafe contexts). Un bloque de iterador siempre define un contexto seguro, incluso cuando su declaración está anidada en un contexto no seguro.An iterator block always defines a safe context, even when its declaration is nested in an unsafe context.
Listas de instruccionesStatement lists
Una *lista de instrucciones _ consta de una o varias instrucciones escritas en secuencia.A *statement list _ consists of one or more statements written in sequence. Las listas de instrucciones se producen en _block * s (bloques) y en Switch_block s (la instrucción switch).Statement lists occur in _block*s (Blocks) and in switch_block s (The switch statement).
statement_list
: statement+
;
Una lista de instrucciones se ejecuta mediante la transferencia de control a la primera instrucción.A statement list is executed by transferring control to the first statement. Cuando y si el control alcanza el punto final de una instrucción, el control se transfiere a la siguiente instrucción.When and if control reaches the end point of a statement, control is transferred to the next statement. Cuando el control alcanza el punto final de la última instrucción, se transfiere el control al punto final de la lista de instrucciones.When and if control reaches the end point of the last statement, control is transferred to the end point of the statement list.
Se puede tener acceso a una instrucción de una lista de instrucciones si se cumple al menos una de las siguientes condiciones:A statement in a statement list is reachable if at least one of the following is true:
- La instrucción es la primera instrucción y la propia lista de instrucciones es accesible.The statement is the first statement and the statement list itself is reachable.
- El punto final de la instrucción anterior es accesible.The end point of the preceding statement is reachable.
- La instrucción es una instrucción con etiqueta y una instrucción accesible hace referencia a la etiqueta
goto
.The statement is a labeled statement and the label is referenced by a reachablegoto
statement.
El punto final de una lista de instrucciones es accesible si el punto final de la última instrucción de la lista es accesible.The end point of a statement list is reachable if the end point of the last statement in the list is reachable.
Instrucción vacíaThe empty statement
Un empty_statement no hace nada.An empty_statement does nothing.
empty_statement
: ';'
;
Se utiliza una instrucción vacía cuando no hay ninguna operación que realizar en un contexto donde se requiere una instrucción.An empty statement is used when there are no operations to perform in a context where a statement is required.
La ejecución de una instrucción vacía simplemente transfiere el control al punto final de la instrucción.Execution of an empty statement simply transfers control to the end point of the statement. Por lo tanto, el punto final de una instrucción vacía es accesible si la instrucción vacía es accesible.Thus, the end point of an empty statement is reachable if the empty statement is reachable.
Se puede usar una instrucción vacía al escribir una while
instrucción con un cuerpo nulo:An empty statement can be used when writing a while
statement with a null body:
bool ProcessMessage() {...}
void ProcessMessages() {
while (ProcessMessage())
;
}
Además, se puede usar una instrucción vacía para declarar una etiqueta justo antes del cierre " }
" de un bloque:Also, an empty statement can be used to declare a label just before the closing "}
" of a block:
void F() {
...
if (done) goto exit;
...
exit: ;
}
Instrucciones con etiquetaLabeled statements
Un labeled_statement permite a una instrucción ir precedida por una etiqueta.A labeled_statement permits a statement to be prefixed by a label. Las instrucciones con etiqueta se permiten en bloques, pero no se permiten como instrucciones incrustadas.Labeled statements are permitted in blocks, but are not permitted as embedded statements.
labeled_statement
: identifier ':' statement
;
Una instrucción con etiqueta declara una etiqueta con el nombre proporcionado por el identificador.A labeled statement declares a label with the name given by the identifier. El ámbito de una etiqueta es el bloque entero en el que se declara la etiqueta, incluidos los bloques anidados.The scope of a label is the whole block in which the label is declared, including any nested blocks. Es un error en tiempo de compilación que dos etiquetas con el mismo nombre tienen ámbitos superpuestos.It is a compile-time error for two labels with the same name to have overlapping scopes.
Se puede hacer referencia a una etiqueta desde goto
instrucciones (instrucción Goto) dentro del ámbito de la etiqueta.A label can be referenced from goto
statements (The goto statement) within the scope of the label. Esto significa que las goto
instrucciones pueden transferir el control dentro de los bloques y fuera de los bloques, pero nunca a los bloques.This means that goto
statements can transfer control within blocks and out of blocks, but never into blocks.
Las etiquetas tienen su propio espacio de declaración y no interfieren con otros identificadores.Labels have their own declaration space and do not interfere with other identifiers. En el ejemploThe example
int F(int x) {
if (x >= 0) goto x;
x = -x;
x: return x;
}
es válido y usa el nombre x
como un parámetro y una etiqueta.is valid and uses the name x
as both a parameter and a label.
La ejecución de una instrucción con etiqueta corresponde exactamente a la ejecución de la instrucción que sigue a la etiqueta.Execution of a labeled statement corresponds exactly to execution of the statement following the label.
Además de la disponibilidad proporcionada por el flujo de control normal, se puede tener acceso a una instrucción con etiqueta si se hace referencia a la etiqueta mediante una goto
instrucción alcanzable.In addition to the reachability provided by normal flow of control, a labeled statement is reachable if the label is referenced by a reachable goto
statement. (Excepción: Si una goto
instrucción está dentro de un try
que incluye un finally
bloque y la instrucción con etiqueta está fuera de try
, y el punto final del finally
bloque es inaccesible, la instrucción con etiqueta no es accesible desde esa goto
instrucción).(Exception: If a goto
statement is inside a try
that includes a finally
block, and the labeled statement is outside the try
, and the end point of the finally
block is unreachable, then the labeled statement is not reachable from that goto
statement.)
Instrucciones de declaraciónDeclaration statements
Un declaration_statement declara una variable o constante local.A declaration_statement declares a local variable or constant. Las instrucciones de declaración se permiten en bloques, pero no se permiten como instrucciones incrustadas.Declaration statements are permitted in blocks, but are not permitted as embedded statements.
declaration_statement
: local_variable_declaration ';'
| local_constant_declaration ';'
;
Declaraciones de variables localesLocal variable declarations
Un local_variable_declaration declara una o más variables locales.A local_variable_declaration declares one or more local variables.
local_variable_declaration
: local_variable_type local_variable_declarators
;
local_variable_type
: type
| 'var'
;
local_variable_declarators
: local_variable_declarator
| local_variable_declarators ',' local_variable_declarator
;
local_variable_declarator
: identifier
| identifier '=' local_variable_initializer
;
local_variable_initializer
: expression
| array_initializer
| local_variable_initializer_unsafe
;
El local_variable_type de una local_variable_declaration especifica directamente el tipo de las variables introducidas por la declaración, o indica con el identificador var
que el tipo se debe inferir en función de un inicializador.The local_variable_type of a local_variable_declaration either directly specifies the type of the variables introduced by the declaration, or indicates with the identifier var
that the type should be inferred based on an initializer. El tipo va seguido de una lista de local_variable_declarator s, cada uno de los cuales introduce una nueva variable.The type is followed by a list of local_variable_declarator s, each of which introduces a new variable. Un local_variable_declarator consta de un identificador que asigna un nombre a la variable, seguido opcionalmente por un =
token "" y un local_variable_initializer que proporciona el valor inicial de la variable.A local_variable_declarator consists of an identifier that names the variable, optionally followed by an "=
" token and a local_variable_initializer that gives the initial value of the variable.
En el contexto de una declaración de variable local, el identificador var actúa como una palabra clave contextual (palabras clave). Cuando el local_variable_type se especifica como var
y ningún tipo denominado var
está en el ámbito, la declaración es una declaración de variable local con tipo implícito, cuyo tipo se deduce del tipo de la expresión de inicializador asociada.In the context of a local variable declaration, the identifier var acts as a contextual keyword (Keywords).When the local_variable_type is specified as var
and no type named var
is in scope, the declaration is an implicitly typed local variable declaration, whose type is inferred from the type of the associated initializer expression. Las declaraciones de variables locales con tipo implícito están sujetas a las siguientes restricciones:Implicitly typed local variable declarations are subject to the following restrictions:
- El local_variable_declaration no puede incluir varios local_variable_declarator s.The local_variable_declaration cannot include multiple local_variable_declarator s.
- El local_variable_declarator debe incluir un local_variable_initializer.The local_variable_declarator must include a local_variable_initializer.
- El local_variable_initializer debe ser una expresión.The local_variable_initializer must be an expression.
- La expresión de inicializador debe tener un tipo en tiempo de compilación.The initializer expression must have a compile-time type.
- La expresión de inicializador no puede hacer referencia a la variable declarada en sí mismaThe initializer expression cannot refer to the declared variable itself
A continuación se muestran ejemplos de declaraciones de variables locales con tipo implícito incorrectas:The following are examples of incorrect implicitly typed local variable declarations:
var x; // Error, no initializer to infer type from
var y = {1, 2, 3}; // Error, array initializer not permitted
var z = null; // Error, null does not have a type
var u = x => x + 1; // Error, anonymous functions do not have a type
var v = v++; // Error, initializer cannot refer to variable itself
El valor de una variable local se obtiene en una expresión usando un simple_name (nombres simples) y el valor de una variable local se modifica mediante una asignación (operadores de asignación).The value of a local variable is obtained in an expression using a simple_name (Simple names), and the value of a local variable is modified using an assignment (Assignment operators). Una variable local debe estar asignada definitivamente (asignación definitiva) en cada ubicación donde se obtiene su valor.A local variable must be definitely assigned (Definite assignment) at each location where its value is obtained.
El ámbito de una variable local declarada en un local_variable_declaration es el bloque en el que se produce la declaración.The scope of a local variable declared in a local_variable_declaration is the block in which the declaration occurs. Es un error hacer referencia a una variable local en una posición textual que precede al local_variable_declarator de la variable local.It is an error to refer to a local variable in a textual position that precedes the local_variable_declarator of the local variable. Dentro del ámbito de una variable local, se trata de un error en tiempo de compilación para declarar otra variable o constante local con el mismo nombre.Within the scope of a local variable, it is a compile-time error to declare another local variable or constant with the same name.
Una declaración de variable local que declara varias variables es equivalente a varias declaraciones de variables únicas con el mismo tipo.A local variable declaration that declares multiple variables is equivalent to multiple declarations of single variables with the same type. Además, un inicializador de variable en una declaración de variable local se corresponde exactamente con una instrucción de asignación que se inserta inmediatamente después de la declaración.Furthermore, a variable initializer in a local variable declaration corresponds exactly to an assignment statement that is inserted immediately after the declaration.
En el ejemploThe example
void F() {
int x = 1, y, z = x * 2;
}
corresponde exactamente acorresponds exactly to
void F() {
int x; x = 1;
int y;
int z; z = x * 2;
}
En una declaración de variable local con tipo implícito, el tipo de la variable local que se está declarando se toma como el mismo tipo de la expresión que se usa para inicializar la variable.In an implicitly typed local variable declaration, the type of the local variable being declared is taken to be the same as the type of the expression used to initialize the variable. Por ejemplo:For example:
var i = 5;
var s = "Hello";
var d = 1.0;
var numbers = new int[] {1, 2, 3};
var orders = new Dictionary<int,Order>();
Las declaraciones de variables locales con tipo implícito anterior son exactamente equivalentes a las siguientes declaraciones con tipo explícito:The implicitly typed local variable declarations above are precisely equivalent to the following explicitly typed declarations:
int i = 5;
string s = "Hello";
double d = 1.0;
int[] numbers = new int[] {1, 2, 3};
Dictionary<int,Order> orders = new Dictionary<int,Order>();
Declaraciones de constantes localesLocal constant declarations
Un local_constant_declaration declara una o más constantes locales.A local_constant_declaration declares one or more local constants.
local_constant_declaration
: 'const' type constant_declarators
;
constant_declarators
: constant_declarator (',' constant_declarator)*
;
constant_declarator
: identifier '=' constant_expression
;
El tipo de un local_constant_declaration especifica el tipo de las constantes introducidas por la declaración.The type of a local_constant_declaration specifies the type of the constants introduced by the declaration. El tipo va seguido de una lista de constant_declarator s, cada uno de los cuales introduce una nueva constante.The type is followed by a list of constant_declarator s, each of which introduces a new constant. Un constant_declarator consta de un identificador que nombra la constante, seguido de un token " =
", seguido de un constant_expression (expresiones constantes) que proporciona el valor de la constante.A constant_declarator consists of an identifier that names the constant, followed by an "=
" token, followed by a constant_expression (Constant expressions) that gives the value of the constant.
El tipo y la constant_expression de una declaración de constante local deben seguir las mismas reglas que las de una declaración de miembro constante (constantes).The type and constant_expression of a local constant declaration must follow the same rules as those of a constant member declaration (Constants).
El valor de una constante local se obtiene en una expresión usando un simple_name (nombres simples).The value of a local constant is obtained in an expression using a simple_name (Simple names).
El ámbito de una constante local es el bloque en el que se produce la declaración.The scope of a local constant is the block in which the declaration occurs. Es un error hacer referencia a una constante local en una posición textual que precede a su constant_declarator.It is an error to refer to a local constant in a textual position that precedes its constant_declarator. Dentro del ámbito de una constante local, es un error en tiempo de compilación declarar otra variable o constante local con el mismo nombre.Within the scope of a local constant, it is a compile-time error to declare another local variable or constant with the same name.
Una declaración de constante local que declara varias constantes es equivalente a varias declaraciones de constantes únicas con el mismo tipo.A local constant declaration that declares multiple constants is equivalent to multiple declarations of single constants with the same type.
Instrucciones de expresiónExpression statements
Un expression_statement evalúa una expresión determinada.An expression_statement evaluates a given expression. El valor calculado por la expresión, si existe, se descarta.The value computed by the expression, if any, is discarded.
expression_statement
: statement_expression ';'
;
statement_expression
: invocation_expression
| null_conditional_invocation_expression
| object_creation_expression
| assignment
| post_increment_expression
| post_decrement_expression
| pre_increment_expression
| pre_decrement_expression
| await_expression
;
No todas las expresiones se permiten como instrucciones.Not all expressions are permitted as statements. En concreto, las expresiones como x + y
y x == 1
que simplemente calculan un valor (que se descartarán) no se permiten como instrucciones.In particular, expressions such as x + y
and x == 1
that merely compute a value (which will be discarded), are not permitted as statements.
La ejecución de una expression_statement evalúa la expresión contenida y, a continuación, transfiere el control al punto final de la expression_statement.Execution of an expression_statement evaluates the contained expression and then transfers control to the end point of the expression_statement. El punto final de una expression_statement es accesible si ese expression_statement es accesible.The end point of an expression_statement is reachable if that expression_statement is reachable.
Instrucciones de selecciónSelection statements
Las instrucciones de selección seleccionan una de varias instrucciones posibles para su ejecución según el valor de alguna expresión.Selection statements select one of a number of possible statements for execution based on the value of some expression.
selection_statement
: if_statement
| switch_statement
;
Instrucción IfThe if statement
La if
instrucción selecciona una instrucción para su ejecución basada en el valor de una expresión booleana.The if
statement selects a statement for execution based on the value of a boolean expression.
if_statement
: 'if' '(' boolean_expression ')' embedded_statement
| 'if' '(' boolean_expression ')' embedded_statement 'else' embedded_statement
;
Un else
elemento está asociado a la parte anterior léxicamente más cercana if
permitida por la sintaxis.An else
part is associated with the lexically nearest preceding if
that is allowed by the syntax. Por lo tanto, una if
instrucción con el formatoThus, an if
statement of the form
if (x) if (y) F(); else G();
es equivalente ais equivalent to
if (x) {
if (y) {
F();
}
else {
G();
}
}
Una if
instrucción se ejecuta de la siguiente manera:An if
statement is executed as follows:
- Se evalúa el Boolean_expression (Expresiones booleanas).The boolean_expression (Boolean expressions) is evaluated.
- Si la expresión booleana produce
true
, el control se transfiere a la primera instrucción incrustada.If the boolean expression yieldstrue
, control is transferred to the first embedded statement. Cuando y si el control alcanza el punto final de la instrucción, el control se transfiere al punto final de laif
instrucción.When and if control reaches the end point of that statement, control is transferred to the end point of theif
statement. - Si la expresión booleana produce
false
y si unelse
elemento está presente, el control se transfiere a la segunda instrucción incrustada.If the boolean expression yieldsfalse
and if anelse
part is present, control is transferred to the second embedded statement. Cuando y si el control alcanza el punto final de la instrucción, el control se transfiere al punto final de laif
instrucción.When and if control reaches the end point of that statement, control is transferred to the end point of theif
statement. - Si la expresión booleana produce
false
y si unelse
elemento no está presente, el control se transfiere al punto final de laif
instrucción.If the boolean expression yieldsfalse
and if anelse
part is not present, control is transferred to the end point of theif
statement.
La primera instrucción incrustada de una if
instrucción es accesible si la if
instrucción es accesible y la expresión booleana no tiene el valor constante false
.The first embedded statement of an if
statement is reachable if the if
statement is reachable and the boolean expression does not have the constant value false
.
La segunda instrucción incrustada de una if
instrucción, si está presente, es accesible si la if
instrucción es accesible y la expresión booleana no tiene el valor constante true
.The second embedded statement of an if
statement, if present, is reachable if the if
statement is reachable and the boolean expression does not have the constant value true
.
El punto final de una if
instrucción es accesible si el punto final de al menos una de sus instrucciones incrustadas es accesible.The end point of an if
statement is reachable if the end point of at least one of its embedded statements is reachable. Además, el punto final de una if
instrucción sin ninguna else
parte es accesible si la if
instrucción es accesible y la expresión booleana no tiene el valor constante true
.In addition, the end point of an if
statement with no else
part is reachable if the if
statement is reachable and the boolean expression does not have the constant value true
.
La instrucción switchThe switch statement
La instrucción switch selecciona la ejecución de una lista de instrucciones que tiene una etiqueta de conmutador asociada que corresponde al valor de la expresión switch.The switch statement selects for execution a statement list having an associated switch label that corresponds to the value of the switch expression.
switch_statement
: 'switch' '(' expression ')' switch_block
;
switch_block
: '{' switch_section* '}'
;
switch_section
: switch_label+ statement_list
;
switch_label
: 'case' constant_expression ':'
| 'default' ':'
;
Un switch_statement se compone de la palabra clave switch
, seguida de una expresión entre paréntesis (denominada expresión switch), seguida de un switch_block.A switch_statement consists of the keyword switch
, followed by a parenthesized expression (called the switch expression), followed by a switch_block. El switch_block consta de cero o más switch_section s, entre llaves.The switch_block consists of zero or more switch_section s, enclosed in braces. Cada switch_section consta de uno o varios switch_label s seguidos de un statement_list (listas de instrucciones).Each switch_section consists of one or more switch_label s followed by a statement_list (Statement lists).
El tipo de control de una switch
instrucción se establece mediante la expresión switch.The governing type of a switch
statement is established by the switch expression.
- Si el tipo de la expresión switch es
sbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,bool
,char
,string
o un enum_type, o si es el tipo que acepta valores NULL correspondiente a uno de estos tipos, es el tipo de control de laswitch
instrucción.If the type of the switch expression issbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,bool
,char
,string
, or an enum_type, or if it is the nullable type corresponding to one of these types, then that is the governing type of theswitch
statement. - De lo contrario, debe existir exactamente una conversión implícita definida por el usuario (conversiones definidas por el usuario) del tipo de la expresión switch a uno de los siguientes tipos de control posibles:
sbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,,char
string
o, un tipo que acepta valores NULL correspondiente a uno de esos tipos.Otherwise, exactly one user-defined implicit conversion (User-defined conversions) must exist from the type of the switch expression to one of the following possible governing types:sbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,string
, or, a nullable type corresponding to one of those types. - De lo contrario, si no existe ninguna conversión implícita, o si existe más de una conversión implícita de este tipo, se produce un error en tiempo de compilación.Otherwise, if no such implicit conversion exists, or if more than one such implicit conversion exists, a compile-time error occurs.
La expresión constante de cada case
etiqueta debe indicar un valor que se pueda convertir implícitamente (conversiones implícitas) en el tipo aplicable de la switch
instrucción.The constant expression of each case
label must denote a value that is implicitly convertible (Implicit conversions) to the governing type of the switch
statement. Se produce un error en tiempo de compilación si dos o más case
etiquetas de la misma switch
instrucción especifican el mismo valor constante.A compile-time error occurs if two or more case
labels in the same switch
statement specify the same constant value.
Puede haber como máximo una default
etiqueta en una instrucción switch.There can be at most one default
label in a switch statement.
Una switch
instrucción se ejecuta de la siguiente manera:A switch
statement is executed as follows:
- La expresión switch se evalúa y se convierte al tipo aplicable.The switch expression is evaluated and converted to the governing type.
- Si una de las constantes especificadas en una
case
etiqueta en la mismaswitch
instrucción es igual al valor de la expresión switch, el control se transfiere a la lista de instrucciones que sigue a lacase
etiqueta coincidente.If one of the constants specified in acase
label in the sameswitch
statement is equal to the value of the switch expression, control is transferred to the statement list following the matchedcase
label. - Si ninguna de las constantes especificadas en
case
las etiquetas de la mismaswitch
instrucción es igual al valor de la expresión switch y, si hay unadefault
etiqueta, el control se transfiere a la lista de instrucciones que sigue a ladefault
etiqueta.If none of the constants specified incase
labels in the sameswitch
statement is equal to the value of the switch expression, and if adefault
label is present, control is transferred to the statement list following thedefault
label. - Si ninguna de las constantes especificadas en
case
las etiquetas de la mismaswitch
instrucción es igual al valor de la expresión switch y no hay ningunadefault
etiqueta, el control se transfiere al punto final de laswitch
instrucción.If none of the constants specified incase
labels in the sameswitch
statement is equal to the value of the switch expression, and if nodefault
label is present, control is transferred to the end point of theswitch
statement.
Si el punto final de la lista de instrucciones de una sección switch es accesible, se producirá un error en tiempo de compilación.If the end point of the statement list of a switch section is reachable, a compile-time error occurs. Esto se conoce como la regla "no pasar de un paso".This is known as the "no fall through" rule. En el ejemploThe example
switch (i) {
case 0:
CaseZero();
break;
case 1:
CaseOne();
break;
default:
CaseOthers();
break;
}
es válido porque ninguna sección del modificador tiene un punto final alcanzable.is valid because no switch section has a reachable end point. A diferencia de C y C++, no se permite la ejecución de una sección switch a la siguiente sección switch y el ejemploUnlike C and C++, execution of a switch section is not permitted to "fall through" to the next switch section, and the example
switch (i) {
case 0:
CaseZero();
case 1:
CaseZeroOrOne();
default:
CaseAny();
}
produce un error en tiempo de compilación.results in a compile-time error. Cuando la ejecución de una sección switch va seguida de la ejecución de otra sección switch, goto case
goto default
se debe usar una instrucción or explícita:When execution of a switch section is to be followed by execution of another switch section, an explicit goto case
or goto default
statement must be used:
switch (i) {
case 0:
CaseZero();
goto case 1;
case 1:
CaseZeroOrOne();
goto default;
default:
CaseAny();
break;
}
En un switch_section se permiten varias etiquetas.Multiple labels are permitted in a switch_section. En el ejemploThe example
switch (i) {
case 0:
CaseZero();
break;
case 1:
CaseOne();
break;
case 2:
default:
CaseTwo();
break;
}
es válido.is valid. En el ejemplo no se infringe la regla "no hay que pasar" porque las etiquetas case 2:
y default:
forman parte del mismo switch_section.The example does not violate the "no fall through" rule because the labels case 2:
and default:
are part of the same switch_section.
La regla "no pasar" evita una clase común de errores que se producen en C y C++ cuando las break
instrucciones se omiten accidentalmente.The "no fall through" rule prevents a common class of bugs that occur in C and C++ when break
statements are accidentally omitted. Además, debido a esta regla, las secciones switch de una switch
instrucción se pueden reorganizar arbitrariamente sin afectar al comportamiento de la instrucción.In addition, because of this rule, the switch sections of a switch
statement can be arbitrarily rearranged without affecting the behavior of the statement. Por ejemplo, las secciones de la switch
instrucción anterior se pueden revertir sin afectar al comportamiento de la instrucción:For example, the sections of the switch
statement above can be reversed without affecting the behavior of the statement:
switch (i) {
default:
CaseAny();
break;
case 1:
CaseZeroOrOne();
goto default;
case 0:
CaseZero();
goto case 1;
}
La lista de instrucciones de una sección switch normalmente finaliza en break
una goto case
instrucción, o goto default
, pero se permite cualquier construcción que representa el punto final de la lista de instrucciones inaccesible.The statement list of a switch section typically ends in a break
, goto case
, or goto default
statement, but any construct that renders the end point of the statement list unreachable is permitted. Por ejemplo, while
se sabe que una instrucción controlada por la expresión booleana true
nunca alcanza su punto final.For example, a while
statement controlled by the boolean expression true
is known to never reach its end point. Del mismo modo, una throw
return
instrucción o siempre transfiere el control en otro lugar y nunca alcanza su punto final.Likewise, a throw
or return
statement always transfers control elsewhere and never reaches its end point. Por lo tanto, el ejemplo siguiente es válido:Thus, the following example is valid:
switch (i) {
case 0:
while (true) F();
case 1:
throw new ArgumentException();
case 2:
return;
}
El tipo de control de una switch
instrucción puede ser el tipo string
.The governing type of a switch
statement may be the type string
. Por ejemplo:For example:
void DoCommand(string command) {
switch (command.ToLower()) {
case "run":
DoRun();
break;
case "save":
DoSave();
break;
case "quit":
DoQuit();
break;
default:
InvalidCommand(command);
break;
}
}
Al igual que los operadores de igualdad de cadena (operadores de igualdad de cadena), la instrucción distingue switch
entre mayúsculas y minúsculas y ejecutará una sección de modificador determinada solo si la cadena de expresión de modificador coincide exactamente con una case
constante de etiqueta.Like the string equality operators (String equality operators), the switch
statement is case sensitive and will execute a given switch section only if the switch expression string exactly matches a case
label constant.
Cuando el tipo de control de una switch
instrucción es string
, null
se permite el valor como una constante de etiqueta de caso.When the governing type of a switch
statement is string
, the value null
is permitted as a case label constant.
Los statement_list s de un switch_block pueden contener instrucciones de declaración (instrucciones de declaración).The statement_list s of a switch_block may contain declaration statements (Declaration statements). El ámbito de una variable local o constante declarada en un bloque switch es el bloque switch.The scope of a local variable or constant declared in a switch block is the switch block.
La lista de instrucciones de una sección de modificador determinada es accesible si la switch
instrucción es accesible y se cumple al menos una de las siguientes condiciones:The statement list of a given switch section is reachable if the switch
statement is reachable and at least one of the following is true:
- La expresión switch es un valor que no es constante.The switch expression is a non-constant value.
- La expresión switch es un valor constante que coincide con una
case
etiqueta en la sección switch.The switch expression is a constant value that matches acase
label in the switch section. - La expresión switch es un valor constante que no coincide con ninguna
case
etiqueta y la sección switch contiene ladefault
etiqueta.The switch expression is a constant value that doesn't match anycase
label, and the switch section contains thedefault
label. - Se hace referencia a una etiqueta switch de la sección switch mediante una
goto case
instrucción o alcanzablegoto default
.A switch label of the switch section is referenced by a reachablegoto case
orgoto default
statement.
El punto final de una switch
instrucción es accesible si se cumple al menos una de las siguientes condiciones:The end point of a switch
statement is reachable if at least one of the following is true:
- La
switch
instrucción contiene una instrucción accesiblebreak
que sale de laswitch
instrucción.Theswitch
statement contains a reachablebreak
statement that exits theswitch
statement. - La
switch
instrucción es accesible, la expresión switch es un valor no constante y no hay ningunadefault
etiqueta.Theswitch
statement is reachable, the switch expression is a non-constant value, and nodefault
label is present. - La
switch
instrucción es accesible, la expresión switch es un valor constante que no coincide con ningunacase
etiqueta y no hay ningunadefault
etiqueta.Theswitch
statement is reachable, the switch expression is a constant value that doesn't match anycase
label, and nodefault
label is present.
Instrucciones de iteraciónIteration statements
Las instrucciones de iteración ejecutan repetidamente una instrucción incrustada.Iteration statements repeatedly execute an embedded statement.
iteration_statement
: while_statement
| do_statement
| for_statement
| foreach_statement
;
La instrucción whileThe while statement
La while
instrucción ejecuta condicionalmente una instrucción incrustada cero o más veces.The while
statement conditionally executes an embedded statement zero or more times.
while_statement
: 'while' '(' boolean_expression ')' embedded_statement
;
Una while
instrucción se ejecuta de la siguiente manera:A while
statement is executed as follows:
- Se evalúa el Boolean_expression (Expresiones booleanas).The boolean_expression (Boolean expressions) is evaluated.
- Si la expresión booleana produce
true
, el control se transfiere a la instrucción incrustada.If the boolean expression yieldstrue
, control is transferred to the embedded statement. Cuando el control alcanza el punto final de la instrucción incrustada (posiblemente desde la ejecución de unacontinue
instrucción), el control se transfiere al principio de lawhile
instrucción.When and if control reaches the end point of the embedded statement (possibly from execution of acontinue
statement), control is transferred to the beginning of thewhile
statement. - Si la expresión booleana produce
false
, el control se transfiere al punto final de lawhile
instrucción.If the boolean expression yieldsfalse
, control is transferred to the end point of thewhile
statement.
Dentro de la instrucción incrustada de una while
instrucción, break
se puede usar una instrucción (la instrucción break) para transferir el control al punto final de la while
instrucción (por lo tanto, finalizar la iteración de la instrucción incrustada) y continue
se puede usar una instrucción (la instrucción continue) para transferir el control al punto final de la instrucción incrustada (por lo que se realiza otra iteración de la while
instrucciónWithin the embedded statement of a while
statement, a break
statement (The break statement) may be used to transfer control to the end point of the while
statement (thus ending iteration of the embedded statement), and a continue
statement (The continue statement) may be used to transfer control to the end point of the embedded statement (thus performing another iteration of the while
statement).
La instrucción incrustada de una while
instrucción es accesible si la while
instrucción es accesible y la expresión booleana no tiene el valor constante false
.The embedded statement of a while
statement is reachable if the while
statement is reachable and the boolean expression does not have the constant value false
.
El punto final de una while
instrucción es accesible si se cumple al menos una de las siguientes condiciones:The end point of a while
statement is reachable if at least one of the following is true:
- La
while
instrucción contiene una instrucción accesiblebreak
que sale de lawhile
instrucción.Thewhile
statement contains a reachablebreak
statement that exits thewhile
statement. - La
while
instrucción es accesible y la expresión booleana no tiene el valor constantetrue
.Thewhile
statement is reachable and the boolean expression does not have the constant valuetrue
.
La instrucción doThe do statement
La do
instrucción ejecuta condicionalmente una instrucción incrustada una o varias veces.The do
statement conditionally executes an embedded statement one or more times.
do_statement
: 'do' embedded_statement 'while' '(' boolean_expression ')' ';'
;
Una do
instrucción se ejecuta de la siguiente manera:A do
statement is executed as follows:
- El control se transfiere a la instrucción insertada.Control is transferred to the embedded statement.
- Cuando el control alcanza el punto final de la instrucción incrustada (posiblemente desde la ejecución de una
continue
instrucción), se evalúa el Boolean_expression (Expresiones booleanas).When and if control reaches the end point of the embedded statement (possibly from execution of acontinue
statement), the boolean_expression (Boolean expressions) is evaluated. Si la expresión booleana producetrue
, el control se transfiere al principio de lado
instrucción.If the boolean expression yieldstrue
, control is transferred to the beginning of thedo
statement. De lo contrario, el control se transfiere al punto final de lado
instrucción.Otherwise, control is transferred to the end point of thedo
statement.
Dentro de la instrucción incrustada de una do
instrucción, break
se puede usar una instrucción (la instrucción break) para transferir el control al punto final de la do
instrucción (por lo tanto, finalizar la iteración de la instrucción incrustada) y continue
se puede usar una instrucción (la instrucción continue) para transferir el control al punto final de la instrucción incrustada.Within the embedded statement of a do
statement, a break
statement (The break statement) may be used to transfer control to the end point of the do
statement (thus ending iteration of the embedded statement), and a continue
statement (The continue statement) may be used to transfer control to the end point of the embedded statement.
La instrucción insertada de una do
instrucción es accesible si la do
instrucción es accesible.The embedded statement of a do
statement is reachable if the do
statement is reachable.
El punto final de una do
instrucción es accesible si se cumple al menos una de las siguientes condiciones:The end point of a do
statement is reachable if at least one of the following is true:
- La
do
instrucción contiene una instrucción accesiblebreak
que sale de lado
instrucción.Thedo
statement contains a reachablebreak
statement that exits thedo
statement. - El punto final de la instrucción incrustada es accesible y la expresión booleana no tiene el valor constante
true
.The end point of the embedded statement is reachable and the boolean expression does not have the constant valuetrue
.
La instrucción forThe for statement
La for
instrucción evalúa una secuencia de expresiones de inicialización y, a continuación, mientras una condición es true, ejecuta repetidamente una instrucción incrustada y evalúa una secuencia de expresiones de iteración.The for
statement evaluates a sequence of initialization expressions and then, while a condition is true, repeatedly executes an embedded statement and evaluates a sequence of iteration expressions.
for_statement
: 'for' '(' for_initializer? ';' for_condition? ';' for_iterator? ')' embedded_statement
;
for_initializer
: local_variable_declaration
| statement_expression_list
;
for_condition
: boolean_expression
;
for_iterator
: statement_expression_list
;
statement_expression_list
: statement_expression (',' statement_expression)*
;
El for_initializer, si está presente, consta de un local_variable_declaration (declaraciones de variables locales) o una lista de statement_expression s (instrucciones de expresión) separadas por comas.The for_initializer, if present, consists of either a local_variable_declaration (Local variable declarations) or a list of statement_expression s (Expression statements) separated by commas. El ámbito de una variable local declarada por una for_initializer comienza en el local_variable_declarator de la variable y se extiende hasta el final de la instrucción incrustada.The scope of a local variable declared by a for_initializer starts at the local_variable_declarator for the variable and extends to the end of the embedded statement. El ámbito incluye el for_condition y el for_iterator.The scope includes the for_condition and the for_iterator.
El for_condition, si está presente, debe ser un Boolean_expression (Expresiones booleanas).The for_condition, if present, must be a boolean_expression (Boolean expressions).
El for_iterator, si está presente, consta de una lista de statement_expression s (instrucciones de expresión) separadas por comas.The for_iterator, if present, consists of a list of statement_expression s (Expression statements) separated by commas.
Una instrucción for se ejecuta de la siguiente manera:A for statement is executed as follows:
- Si hay un for_initializer , los inicializadores variables o las expresiones de instrucción se ejecutan en el orden en que se escriben.If a for_initializer is present, the variable initializers or statement expressions are executed in the order they are written. Este paso solo se realiza una vez.This step is only performed once.
- Si hay un for_condition , se evalúa.If a for_condition is present, it is evaluated.
- Si el for_condition no está presente o si la evaluación produce
true
, el control se transfiere a la instrucción insertada.If the for_condition is not present or if the evaluation yieldstrue
, control is transferred to the embedded statement. Cuando el control alcanza el punto final de la instrucción incrustada (posiblemente desde la ejecución de unacontinue
instrucción), las expresiones del for_iterator, si las hubiera, se evalúan en secuencia y, a continuación, se realiza otra iteración, comenzando por la evaluación de la for_condition en el paso anterior.When and if control reaches the end point of the embedded statement (possibly from execution of acontinue
statement), the expressions of the for_iterator, if any, are evaluated in sequence, and then another iteration is performed, starting with evaluation of the for_condition in the step above. - Si el for_condition está presente y la evaluación produce
false
, el control se transfiere al punto final de lafor
instrucción.If the for_condition is present and the evaluation yieldsfalse
, control is transferred to the end point of thefor
statement.
Dentro de la instrucción incrustada de una for
instrucción, break
se puede usar una instrucción (la instrucción break) para transferir el control al punto final de la for
instrucción (con lo que finaliza la iteración de la instrucción incrustada) y continue
se puede usar una instrucción (la instrucción continue) para transferir el control al punto final de la instrucción incrustada (de modo que se ejecute el for_iterator y realice otra iteración de la for
instrucción, empezando por el for_condition)Within the embedded statement of a for
statement, a break
statement (The break statement) may be used to transfer control to the end point of the for
statement (thus ending iteration of the embedded statement), and a continue
statement (The continue statement) may be used to transfer control to the end point of the embedded statement (thus executing the for_iterator and performing another iteration of the for
statement, starting with the for_condition).
La instrucción insertada de una for
instrucción es accesible si se cumple una de las siguientes condiciones:The embedded statement of a for
statement is reachable if one of the following is true:
- La
for
instrucción es accesible y no hay ningún for_condition presente.Thefor
statement is reachable and no for_condition is present. - La
for
instrucción es accesible y hay un for_condition presente y no tiene el valor constantefalse
.Thefor
statement is reachable and a for_condition is present and does not have the constant valuefalse
.
El punto final de una for
instrucción es accesible si se cumple al menos una de las siguientes condiciones:The end point of a for
statement is reachable if at least one of the following is true:
- La
for
instrucción contiene una instrucción accesiblebreak
que sale de lafor
instrucción.Thefor
statement contains a reachablebreak
statement that exits thefor
statement. - La
for
instrucción es accesible y hay un for_condition presente y no tiene el valor constantetrue
.Thefor
statement is reachable and a for_condition is present and does not have the constant valuetrue
.
La instrucción foreachThe foreach statement
La foreach
instrucción enumera los elementos de una colección y ejecuta una instrucción incrustada para cada elemento de la colección.The foreach
statement enumerates the elements of a collection, executing an embedded statement for each element of the collection.
foreach_statement
: 'foreach' '(' local_variable_type identifier 'in' expression ')' embedded_statement
;
El tipo y el identificador de una foreach
instrucción declaran la variable de iteración* _ de la instrucción.The type and identifier of a foreach
statement declare the *iteration variable _ of the statement. Si el var
identificador se proporciona como _local_variable_type *, y no hay ningún tipo denominado var
en el ámbito, se dice que la variable de iteración es una variable de iteración con tipo implícito y se considera que su tipo es el tipo de elemento de la foreach
instrucción, tal y como se especifica a continuación.If the var
identifier is given as the _local_variable_type*, and no type named var
is in scope, the iteration variable is said to be an implicitly typed iteration variable, and its type is taken to be the element type of the foreach
statement, as specified below. La variable de iteración corresponde a una variable local de solo lectura con un ámbito que se extiende a través de la instrucción incrustada.The iteration variable corresponds to a read-only local variable with a scope that extends over the embedded statement. Durante la ejecución de una foreach
instrucción, la variable de iteración representa el elemento de colección para el que se está realizando actualmente una iteración.During execution of a foreach
statement, the iteration variable represents the collection element for which an iteration is currently being performed. Se produce un error en tiempo de compilación si la instrucción incrustada intenta modificar la variable de iteración (a través de la asignación o los ++
--
operadores y) o pasar la variable de iteración como un ref
out
parámetro o.A compile-time error occurs if the embedded statement attempts to modify the iteration variable (via assignment or the ++
and --
operators) or pass the iteration variable as a ref
or out
parameter.
En el siguiente, por motivos de brevedad, IEnumerable
, IEnumerator
IEnumerable<T>
y IEnumerator<T>
hacen referencia a los tipos correspondientes de los espacios de nombres System.Collections
y System.Collections.Generic
.In the following, for brevity, IEnumerable
, IEnumerator
, IEnumerable<T>
and IEnumerator<T>
refer to the corresponding types in the namespaces System.Collections
and System.Collections.Generic
.
El procesamiento en tiempo de compilación de una instrucción foreach primero determina el tipo de colección _, el tipo de _enumerador_ y el tipo de elemento de la expresión.The compile-time processing of a foreach statement first determines the collection type _, _enumerator type_ and _ element type of the expression. Esta determinación se realiza de la siguiente manera:This determination proceeds as follows:
Si el tipo
X
de expresión es un tipo de matriz, hay una conversión de referencia implícita deX
a laIEnumerable
interfaz (puesto queSystem.Array
implementa esta interfaz).If the typeX
of expression is an array type then there is an implicit reference conversion fromX
to theIEnumerable
interface (sinceSystem.Array
implements this interface). * El tipo de colección _ es laIEnumerable
interfaz, el tipo de enumerador es laIEnumerator
interfaz y el tipo de elemento _ * es el tipo de elemento del tipo de matrizX
.The collection type _ is theIEnumerable
interface, the _enumerator type_ is theIEnumerator
interface and the _ element type is the element type of the array typeX
.Si el tipo
X
de expresión esdynamic
, hay una conversión implícita de la expresión a laIEnumerable
interfaz (conversiones dinámicas implícitas).If the typeX
of expression isdynamic
then there is an implicit conversion from expression to theIEnumerable
interface (Implicit dynamic conversions). * El tipo de colección _ es laIEnumerable
interfaz y el tipo de enumerador es laIEnumerator
interfaz.The collection type _ is theIEnumerable
interface and the _enumerator type*_ is theIEnumerator
interface. Si elvar
identificador se proporciona como _local_variable_type *, el tipo de elemento esdynamic
, de lo contrario, esobject
.If thevar
identifier is given as the _local_variable_type* then the element type isdynamic
, otherwise it isobject
.De lo contrario, determine si el tipo
X
tiene unGetEnumerator
método adecuado:Otherwise, determine whether the typeX
has an appropriateGetEnumerator
method:- Realiza la búsqueda de miembros en el tipo
X
con el identificadorGetEnumerator
y ningún argumento de tipo.Perform member lookup on the typeX
with identifierGetEnumerator
and no type arguments. Si la búsqueda de miembros no produce una coincidencia, o produce una ambigüedad, o produce una coincidencia que no es un grupo de métodos, busque una interfaz enumerable como se describe a continuación.If the member lookup does not produce a match, or it produces an ambiguity, or produces a match that is not a method group, check for an enumerable interface as described below. Se recomienda emitir una advertencia si la búsqueda de miembros produce cualquier cosa, excepto un grupo de métodos o ninguna coincidencia.It is recommended that a warning be issued if member lookup produces anything except a method group or no match. - Realizar la resolución de sobrecarga utilizando el grupo de métodos resultante y una lista de argumentos vacía.Perform overload resolution using the resulting method group and an empty argument list. Si la resolución de sobrecarga da como resultado ningún método aplicable, da como resultado una ambigüedad o tiene como resultado un único método mejor pero ese método es estático o no público, busque una interfaz enumerable como se describe a continuación.If overload resolution results in no applicable methods, results in an ambiguity, or results in a single best method but that method is either static or not public, check for an enumerable interface as described below. Se recomienda emitir una advertencia si la resolución de sobrecarga produce todo excepto un método de instancia pública inequívoco o ningún método aplicable.It is recommended that a warning be issued if overload resolution produces anything except an unambiguous public instance method or no applicable methods.
- Si el tipo de valor devuelto
E
delGetEnumerator
método no es una clase, una estructura o un tipo de interfaz, se genera un error y no se realiza ningún otro paso.If the return typeE
of theGetEnumerator
method is not a class, struct or interface type, an error is produced and no further steps are taken. - La búsqueda de miembros se realiza en
E
con el identificadorCurrent
y sin argumentos de tipo.Member lookup is performed onE
with the identifierCurrent
and no type arguments. Si la búsqueda de miembros no produce ninguna coincidencia, el resultado es un error o el resultado es cualquier cosa excepto una propiedad de instancia pública que permita la lectura, se genera un error y no se realiza ningún paso más.If the member lookup produces no match, the result is an error, or the result is anything except a public instance property that permits reading, an error is produced and no further steps are taken. - La búsqueda de miembros se realiza en
E
con el identificadorMoveNext
y sin argumentos de tipo.Member lookup is performed onE
with the identifierMoveNext
and no type arguments. Si la búsqueda de miembros no produce ninguna coincidencia, el resultado es un error o el resultado es cualquier cosa excepto un grupo de métodos, se genera un error y no se realiza ningún paso más.If the member lookup produces no match, the result is an error, or the result is anything except a method group, an error is produced and no further steps are taken. - La resolución de sobrecarga se realiza en el grupo de métodos con una lista de argumentos vacía.Overload resolution is performed on the method group with an empty argument list. Si la resolución de sobrecarga da como resultado ningún método aplicable, da como resultado una ambigüedad o tiene como resultado un único método mejor pero ese método es estático o no público, o su tipo de valor devuelto no es
bool
, se genera un error y no se realiza ningún otro paso.If overload resolution results in no applicable methods, results in an ambiguity, or results in a single best method but that method is either static or not public, or its return type is notbool
, an error is produced and no further steps are taken. - El tipo de colección* es
X
, el tipo de enumerador esE
y el tipo de elemento _ * es el tipo de laCurrent
propiedad.The collection type _ isX
, the _enumerator type_ isE
, and the _ element type is the type of theCurrent
property.
- Realiza la búsqueda de miembros en el tipo
De lo contrario, compruebe si hay una interfaz enumerable:Otherwise, check for an enumerable interface:
- Si entre todos los tipos
Ti
para los que hay una conversión implícita deX
aIEnumerable<Ti>
, hay un tipo únicoT
, de modo queT
no esdynamic
y para todos los demásTi
hay una conversión implícita deIEnumerable<T>
aIEnumerable<Ti>
, entonces el tipo de colección _ es la interfazIEnumerable<T>
, el tipo de _enumerador*_ es la interfazIEnumerator<T>
y el tipo de elemento _ * esT
.If among all the typesTi
for which there is an implicit conversion fromX
toIEnumerable<Ti>
, there is a unique typeT
such thatT
is notdynamic
and for all the otherTi
there is an implicit conversion fromIEnumerable<T>
toIEnumerable<Ti>
, then the collection type _ is the interfaceIEnumerable<T>
, the _enumerator type_ is the interfaceIEnumerator<T>
, and the _ element type isT
. - De lo contrario, si hay más de un tipo de este tipo
T
, se genera un error y no se realiza ningún paso más.Otherwise, if there is more than one such typeT
, then an error is produced and no further steps are taken. - De lo contrario, si hay una conversión implícita de
X
en laSystem.Collections.IEnumerable
interfaz, el tipo de colección* _ es esta interfaz, el tipo de enumerador es la interfazSystem.Collections.IEnumerator
y el tipo de elemento _ * esobject
.Otherwise, if there is an implicit conversion fromX
to theSystem.Collections.IEnumerable
interface, then the collection type _ is this interface, the _enumerator type_ is the interfaceSystem.Collections.IEnumerator
, and the _ element type isobject
. - De lo contrario, se genera un error y no se realiza ningún paso más.Otherwise, an error is produced and no further steps are taken.
- Si entre todos los tipos
Los pasos anteriores, si son correctos, producen de forma inequívoca un tipo de colección, un tipo C
de enumerador E
y un tipo de elemento T
.The above steps, if successful, unambiguously produce a collection type C
, enumerator type E
and element type T
. Una instrucción foreach con el formatoA foreach statement of the form
foreach (V v in x) embedded_statement
se expande a continuación hasta:is then expanded to:
{
E e = ((C)(x)).GetEnumerator();
try {
while (e.MoveNext()) {
V v = (V)(T)e.Current;
embedded_statement
}
}
finally {
... // Dispose e
}
}
La variable e
no es visible o accesible para la expresión x
o la instrucción incrustada ni cualquier otro código fuente del programa.The variable e
is not visible to or accessible to the expression x
or the embedded statement or any other source code of the program. La variable v
es de solo lectura en la instrucción insertada.The variable v
is read-only in the embedded statement. Si no hay una conversión explícita (conversiones explícitas) de T
(el tipo de elemento) en V
(el local_variable_type en la instrucción foreach), se genera un error y no se realiza ningún paso más.If there is not an explicit conversion (Explicit conversions) from T
(the element type) to V
(the local_variable_type in the foreach statement), an error is produced and no further steps are taken. Si x
tiene el valor null
, System.NullReferenceException
se produce una excepción en tiempo de ejecución.If x
has the value null
, a System.NullReferenceException
is thrown at run-time.
Una implementación puede implementar una instrucción foreach determinada de forma diferente, por ejemplo, por motivos de rendimiento, siempre que el comportamiento sea coherente con la expansión anterior.An implementation is permitted to implement a given foreach-statement differently, e.g. for performance reasons, as long as the behavior is consistent with the above expansion.
La colocación de v
dentro del bucle while es importante para que lo Capture cualquier función anónima que se produzca en el embedded_statement.The placement of v
inside the while loop is important for how it is captured by any anonymous function occurring in the embedded_statement.
Por ejemplo:For example:
int[] values = { 7, 9, 13 };
Action f = null;
foreach (var value in values)
{
if (f == null) f = () => Console.WriteLine("First value: " + value);
}
f();
Si v
se declaró fuera del bucle while, se compartirá entre todas las iteraciones y su valor después del bucle for sería el valor final, 13
, que es lo que la invocación de f
imprimiría.If v
was declared outside of the while loop, it would be shared among all iterations, and its value after the for loop would be the final value, 13
, which is what the invocation of f
would print. En su lugar, dado que cada iteración tiene su propia variable v
, la f
que captura en la primera iteración seguirá conservando el valor 7
, que es lo que se va a imprimir.Instead, because each iteration has its own variable v
, the one captured by f
in the first iteration will continue to hold the value 7
, which is what will be printed. (Nota: versiones anteriores de C# declaradas v
fuera del bucle while).(Note: earlier versions of C# declared v
outside of the while loop.)
El cuerpo del bloque finally se construye según los pasos siguientes:The body of the finally block is constructed according to the following steps:
Si hay una conversión implícita de
E
en laSystem.IDisposable
interfaz,If there is an implicit conversion fromE
to theSystem.IDisposable
interface, thenSi
E
es un tipo de valor que no acepta valores NULL, la cláusula finally se expande al equivalente semántico de:IfE
is a non-nullable value type then the finally clause is expanded to the semantic equivalent of:finally { ((System.IDisposable)e).Dispose(); }
En caso contrario, la cláusula finally se expande al equivalente semántico de:Otherwise the finally clause is expanded to the semantic equivalent of:
finally { if (e != null) ((System.IDisposable)e).Dispose(); }
salvo que si
E
es un tipo de valor o un parámetro de tipo al que se ha creado una instancia de un tipo de valor, la conversión dee
aSystem.IDisposable
no hará que se produzca la conversión boxing.except that ifE
is a value type, or a type parameter instantiated to a value type, then the cast ofe
toSystem.IDisposable
will not cause boxing to occur.De lo contrario, si
E
es un tipo sellado, la cláusula finally se expande a un bloque vacío:Otherwise, ifE
is a sealed type, the finally clause is expanded to an empty block:finally { }
De lo contrario, la cláusula finally se expande a:Otherwise, the finally clause is expanded to:
finally { System.IDisposable d = e as System.IDisposable; if (d != null) d.Dispose(); }
La variable local
d
no es visible o accesible para cualquier código de usuario.The local variabled
is not visible to or accessible to any user code. En concreto, no entra en conflicto con ninguna otra variable cuyo ámbito incluya el bloque Finally.In particular, it does not conflict with any other variable whose scope includes the finally block.
El orden en el que se foreach
recorren los elementos de una matriz es el siguiente: en el caso de las matrices unidimensionales, los elementos se recorren en orden creciente de índice, empezando por el índice 0
y terminando por el índice Length - 1
.The order in which foreach
traverses the elements of an array, is as follows: For single-dimensional arrays elements are traversed in increasing index order, starting with index 0
and ending with index Length - 1
. En el caso de las matrices multidimensionales, los elementos se recorren de forma que los índices de la dimensión situada más a la derecha aumenten primero, la dimensión izquierda siguiente y así sucesivamente hacia la izquierda.For multi-dimensional arrays, elements are traversed such that the indices of the rightmost dimension are increased first, then the next left dimension, and so on to the left.
En el ejemplo siguiente se imprime cada valor en una matriz bidimensional, en el orden de los elementos:The following example prints out each value in a two-dimensional array, in element order:
using System;
class Test
{
static void Main() {
double[,] values = {
{1.2, 2.3, 3.4, 4.5},
{5.6, 6.7, 7.8, 8.9}
};
foreach (double elementValue in values)
Console.Write("{0} ", elementValue);
Console.WriteLine();
}
}
La salida generada es la siguiente:The output produced is as follows:
1.2 2.3 3.4 4.5 5.6 6.7 7.8 8.9
En el ejemploIn the example
int[] numbers = { 1, 3, 5, 7, 9 };
foreach (var n in numbers) Console.WriteLine(n);
el tipo de n
se deduce como int
, el tipo de elemento de numbers
.the type of n
is inferred to be int
, the element type of numbers
.
Instrucciones de saltoJump statements
Las instrucciones de salto transfieren el control incondicionalmente.Jump statements unconditionally transfer control.
jump_statement
: break_statement
| continue_statement
| goto_statement
| return_statement
| throw_statement
;
La ubicación a la que una instrucción de salto transfiere el control se denomina destino de la instrucción de salto.The location to which a jump statement transfers control is called the target of the jump statement.
Cuando una instrucción de salto se produce dentro de un bloque y el destino de la instrucción de salto está fuera del bloque, se dice que la instrucción de salto sale del bloque.When a jump statement occurs within a block, and the target of that jump statement is outside that block, the jump statement is said to exit the block. Aunque una instrucción de salto puede transferir el control fuera de un bloque, nunca puede transferir el control a un bloque.While a jump statement may transfer control out of a block, it can never transfer control into a block.
La ejecución de instrucciones de salto es complicada por la presencia de instrucciones intermedias try
.Execution of jump statements is complicated by the presence of intervening try
statements. En ausencia de estas try
instrucciones, una instrucción de salto transfiere incondicionalmente el control de la instrucción de salto a su destino.In the absence of such try
statements, a jump statement unconditionally transfers control from the jump statement to its target. En presencia de dichas instrucciones intermedias try
, la ejecución es más compleja.In the presence of such intervening try
statements, execution is more complex. Si la instrucción de salto sale de uno o más try
bloques con finally
bloques asociados, el control se transfiere inicialmente al finally
bloque de la try
instrucción más interna.If the jump statement exits one or more try
blocks with associated finally
blocks, control is initially transferred to the finally
block of the innermost try
statement. Cuando y si el control alcanza el punto final de un finally
bloque, el control se transfiere al finally
bloque de la siguiente instrucción de inclusión try
.When and if control reaches the end point of a finally
block, control is transferred to the finally
block of the next enclosing try
statement. Este proceso se repite hasta que finally
se hayan ejecutado los bloques de todas las instrucciones que intervienen try
.This process is repeated until the finally
blocks of all intervening try
statements have been executed.
En el ejemploIn the example
using System;
class Test
{
static void Main() {
while (true) {
try {
try {
Console.WriteLine("Before break");
break;
}
finally {
Console.WriteLine("Innermost finally block");
}
}
finally {
Console.WriteLine("Outermost finally block");
}
}
Console.WriteLine("After break");
}
}
los finally
bloques asociados a dos try
instrucciones se ejecutan antes de que el control se transfiera al destino de la instrucción de salto.the finally
blocks associated with two try
statements are executed before control is transferred to the target of the jump statement.
La salida generada es la siguiente:The output produced is as follows:
Before break
Innermost finally block
Outermost finally block
After break
Instrucción breakThe break statement
La break
instrucción sale de la instrucción de inclusión,,, o más cercana switch
while
do
for
foreach
.The break
statement exits the nearest enclosing switch
, while
, do
, for
, or foreach
statement.
break_statement
: 'break' ';'
;
El destino de una break
instrucción es el punto final de la switch
instrucción envolvente,,, o más cercana while
do
for
foreach
.The target of a break
statement is the end point of the nearest enclosing switch
, while
, do
, for
, or foreach
statement. Si una break
instrucción no está delimitada por switch
una while
instrucción,, do
, for
o foreach
, se produce un error en tiempo de compilación.If a break
statement is not enclosed by a switch
, while
, do
, for
, or foreach
statement, a compile-time error occurs.
Cuando varias switch
instrucciones,,, while
do
for
o foreach
se anidan entre sí, una break
instrucción solo se aplica a la instrucción más interna.When multiple switch
, while
, do
, for
, or foreach
statements are nested within each other, a break
statement applies only to the innermost statement. Para transferir el control entre varios niveles de anidamiento, goto
se debe usar una instrucción (instrucción Goto).To transfer control across multiple nesting levels, a goto
statement (The goto statement) must be used.
Una break
instrucción no puede salir de un finally
bloque (la instrucción try).A break
statement cannot exit a finally
block (The try statement). Cuando una break
instrucción aparece dentro de un finally
bloque, el destino de la break
instrucción debe estar dentro del mismo finally
bloque; de lo contrario, se produce un error en tiempo de compilación.When a break
statement occurs within a finally
block, the target of the break
statement must be within the same finally
block; otherwise, a compile-time error occurs.
Una break
instrucción se ejecuta de la siguiente manera:A break
statement is executed as follows:
- Si la
break
instrucción sale de uno o mástry
bloques confinally
bloques asociados, el control se transfiere inicialmente alfinally
bloque de la instrucción más internatry
.If thebreak
statement exits one or moretry
blocks with associatedfinally
blocks, control is initially transferred to thefinally
block of the innermosttry
statement. Cuando y si el control alcanza el punto final de unfinally
bloque, el control se transfiere alfinally
bloque de la siguiente instrucción de inclusióntry
.When and if control reaches the end point of afinally
block, control is transferred to thefinally
block of the next enclosingtry
statement. Este proceso se repite hasta quefinally
se hayan ejecutado los bloques de todas las instrucciones que intervienentry
.This process is repeated until thefinally
blocks of all interveningtry
statements have been executed. - El control se transfiere al destino de la
break
instrucción.Control is transferred to the target of thebreak
statement.
Dado break
que una instrucción transfiere el control incondicionalmente a otra parte, el punto final de una break
instrucción nunca es accesible.Because a break
statement unconditionally transfers control elsewhere, the end point of a break
statement is never reachable.
La instrucción continueThe continue statement
La continue
instrucción inicia una nueva iteración de la instrucción envolvente while
, do
, for
o más cercana foreach
.The continue
statement starts a new iteration of the nearest enclosing while
, do
, for
, or foreach
statement.
continue_statement
: 'continue' ';'
;
El destino de una continue
instrucción es el punto final de la instrucción incrustada de la instrucción envolvente while
, do
, for
o más cercana foreach
.The target of a continue
statement is the end point of the embedded statement of the nearest enclosing while
, do
, for
, or foreach
statement. Si una continue
instrucción no está delimitada por while
una do
instrucción,, for
o foreach
, se produce un error en tiempo de compilación.If a continue
statement is not enclosed by a while
, do
, for
, or foreach
statement, a compile-time error occurs.
Cuando varias while
do
instrucciones,, for
o foreach
se anidan entre sí, una continue
instrucción solo se aplica a la instrucción más interna.When multiple while
, do
, for
, or foreach
statements are nested within each other, a continue
statement applies only to the innermost statement. Para transferir el control entre varios niveles de anidamiento, goto
se debe usar una instrucción (instrucción Goto).To transfer control across multiple nesting levels, a goto
statement (The goto statement) must be used.
Una continue
instrucción no puede salir de un finally
bloque (la instrucción try).A continue
statement cannot exit a finally
block (The try statement). Cuando una continue
instrucción aparece dentro de un finally
bloque, el destino de la continue
instrucción debe estar dentro del mismo finally
bloque; de lo contrario, se produce un error en tiempo de compilación.When a continue
statement occurs within a finally
block, the target of the continue
statement must be within the same finally
block; otherwise a compile-time error occurs.
Una continue
instrucción se ejecuta de la siguiente manera:A continue
statement is executed as follows:
- Si la
continue
instrucción sale de uno o mástry
bloques confinally
bloques asociados, el control se transfiere inicialmente alfinally
bloque de la instrucción más internatry
.If thecontinue
statement exits one or moretry
blocks with associatedfinally
blocks, control is initially transferred to thefinally
block of the innermosttry
statement. Cuando y si el control alcanza el punto final de unfinally
bloque, el control se transfiere alfinally
bloque de la siguiente instrucción de inclusióntry
.When and if control reaches the end point of afinally
block, control is transferred to thefinally
block of the next enclosingtry
statement. Este proceso se repite hasta quefinally
se hayan ejecutado los bloques de todas las instrucciones que intervienentry
.This process is repeated until thefinally
blocks of all interveningtry
statements have been executed. - El control se transfiere al destino de la
continue
instrucción.Control is transferred to the target of thecontinue
statement.
Dado continue
que una instrucción transfiere el control incondicionalmente a otra parte, el punto final de una continue
instrucción nunca es accesible.Because a continue
statement unconditionally transfers control elsewhere, the end point of a continue
statement is never reachable.
La instrucción gotoThe goto statement
La goto
instrucción transfiere el control a una instrucción marcada por una etiqueta.The goto
statement transfers control to a statement that is marked by a label.
goto_statement
: 'goto' identifier ';'
| 'goto' 'case' constant_expression ';'
| 'goto' 'default' ';'
;
El destino de una goto
instrucción Identifier es la instrucción con etiqueta con la etiqueta especificada.The target of a goto
identifier statement is the labeled statement with the given label. Si no existe una etiqueta con el nombre especificado en el miembro de función actual, o si la goto
instrucción no está dentro del ámbito de la etiqueta, se produce un error en tiempo de compilación.If a label with the given name does not exist in the current function member, or if the goto
statement is not within the scope of the label, a compile-time error occurs. Esta regla permite el uso de una goto
instrucción para transferir el control fuera de un ámbito anidado, pero no a un ámbito anidado.This rule permits the use of a goto
statement to transfer control out of a nested scope, but not into a nested scope. En el ejemploIn the example
using System;
class Test
{
static void Main(string[] args) {
string[,] table = {
{"Red", "Blue", "Green"},
{"Monday", "Wednesday", "Friday"}
};
foreach (string str in args) {
int row, colm;
for (row = 0; row <= 1; ++row)
for (colm = 0; colm <= 2; ++colm)
if (str == table[row,colm])
goto done;
Console.WriteLine("{0} not found", str);
continue;
done:
Console.WriteLine("Found {0} at [{1}][{2}]", str, row, colm);
}
}
}
una goto
instrucción se usa para transferir el control fuera de un ámbito anidado.a goto
statement is used to transfer control out of a nested scope.
El destino de una goto case
instrucción es la lista de instrucciones de la instrucción de inclusión inmediata switch
(la instrucción switch), que contiene una case
etiqueta con el valor constante especificado.The target of a goto case
statement is the statement list in the immediately enclosing switch
statement (The switch statement), which contains a case
label with the given constant value. Si la goto case
instrucción no está delimitada por una switch
instrucción, si el constant_expression no es implícitamente convertible (conversiones implícitas) al tipo aplicable de la instrucción de inclusión más cercana switch
, o si la instrucción de inclusión más cercana no switch
contiene una case
etiqueta con el valor constante especificado, se produce un error en tiempo de compilación.If the goto case
statement is not enclosed by a switch
statement, if the constant_expression is not implicitly convertible (Implicit conversions) to the governing type of the nearest enclosing switch
statement, or if the nearest enclosing switch
statement does not contain a case
label with the given constant value, a compile-time error occurs.
El destino de una goto default
instrucción es la lista de instrucciones de la instrucción de inclusión inmediata switch
(la instrucción switch), que contiene una default
etiqueta.The target of a goto default
statement is the statement list in the immediately enclosing switch
statement (The switch statement), which contains a default
label. Si la goto default
instrucción no está delimitada por una switch
instrucción, o si la instrucción de inclusión más cercana no switch
contiene una default
etiqueta, se produce un error en tiempo de compilación.If the goto default
statement is not enclosed by a switch
statement, or if the nearest enclosing switch
statement does not contain a default
label, a compile-time error occurs.
Una goto
instrucción no puede salir de un finally
bloque (la instrucción try).A goto
statement cannot exit a finally
block (The try statement). Cuando una goto
instrucción aparece dentro de un finally
bloque, el destino de la goto
instrucción debe estar dentro del mismo finally
bloque o, de lo contrario, se producirá un error en tiempo de compilación.When a goto
statement occurs within a finally
block, the target of the goto
statement must be within the same finally
block, or otherwise a compile-time error occurs.
Una goto
instrucción se ejecuta de la siguiente manera:A goto
statement is executed as follows:
- Si la
goto
instrucción sale de uno o mástry
bloques confinally
bloques asociados, el control se transfiere inicialmente alfinally
bloque de la instrucción más internatry
.If thegoto
statement exits one or moretry
blocks with associatedfinally
blocks, control is initially transferred to thefinally
block of the innermosttry
statement. Cuando y si el control alcanza el punto final de unfinally
bloque, el control se transfiere alfinally
bloque de la siguiente instrucción de inclusióntry
.When and if control reaches the end point of afinally
block, control is transferred to thefinally
block of the next enclosingtry
statement. Este proceso se repite hasta quefinally
se hayan ejecutado los bloques de todas las instrucciones que intervienentry
.This process is repeated until thefinally
blocks of all interveningtry
statements have been executed. - El control se transfiere al destino de la
goto
instrucción.Control is transferred to the target of thegoto
statement.
Dado goto
que una instrucción transfiere el control incondicionalmente a otra parte, el punto final de una goto
instrucción nunca es accesible.Because a goto
statement unconditionally transfers control elsewhere, the end point of a goto
statement is never reachable.
La instrucción returnThe return statement
La return
instrucción devuelve el control al llamador actual de la función en la que return
aparece la instrucción.The return
statement returns control to the current caller of the function in which the return
statement appears.
return_statement
: 'return' expression? ';'
;
Una return
instrucción sin expresión solo se puede usar en un miembro de función que no calcule un valor, es decir, un método con el tipo de resultado (cuerpo del método) void
, el set
descriptor de acceso de una propiedad o un indizador, y descriptores add
remove
de acceso de un evento, un constructor de instancia, un constructor estático o un destructor.A return
statement with no expression can be used only in a function member that does not compute a value, that is, a method with the result type (Method body) void
, the set
accessor of a property or indexer, the add
and remove
accessors of an event, an instance constructor, a static constructor, or a destructor.
Una return
instrucción con una expresión solo se puede usar en un miembro de función que calcula un valor, es decir, un método con un tipo de resultado no void, el get
descriptor de acceso de una propiedad o un indizador, o un operador definido por el usuario.A return
statement with an expression can only be used in a function member that computes a value, that is, a method with a non-void result type, the get
accessor of a property or indexer, or a user-defined operator. Debe existir una conversión implícita (conversiones implícitas) del tipo de la expresión al tipo de valor devuelto del miembro de función contenedora.An implicit conversion (Implicit conversions) must exist from the type of the expression to the return type of the containing function member.
Las instrucciones Return también se pueden utilizar en el cuerpo de expresiones de función anónimas (expresiones de función anónimas) y participar en la determinación de las conversiones que existen para esas funciones.Return statements can also be used in the body of anonymous function expressions (Anonymous function expressions), and participate in determining which conversions exist for those functions.
Se trata de un error en tiempo de compilación para return
que una instrucción aparezca en un finally
bloque (la instrucción try).It is a compile-time error for a return
statement to appear in a finally
block (The try statement).
Una return
instrucción se ejecuta de la siguiente manera:A return
statement is executed as follows:
- Si la
return
instrucción especifica una expresión, se evalúa la expresión y el valor resultante se convierte al tipo de valor devuelto de la función que la contiene mediante una conversión implícita.If thereturn
statement specifies an expression, the expression is evaluated and the resulting value is converted to the return type of the containing function by an implicit conversion. El resultado de la conversión se convierte en el valor de resultado producido por la función.The result of the conversion becomes the result value produced by the function. - Si la
return
instrucción está incluida en uno o variostry
catch
bloques o confinally
bloques asociados, el control se transfiere inicialmente alfinally
bloque de la instrucción más internatry
.If thereturn
statement is enclosed by one or moretry
orcatch
blocks with associatedfinally
blocks, control is initially transferred to thefinally
block of the innermosttry
statement. Cuando y si el control alcanza el punto final de unfinally
bloque, el control se transfiere alfinally
bloque de la siguiente instrucción de inclusióntry
.When and if control reaches the end point of afinally
block, control is transferred to thefinally
block of the next enclosingtry
statement. Este proceso se repite hasta quefinally
se hayan ejecutado los bloques de todas las instrucciones envolventestry
.This process is repeated until thefinally
blocks of all enclosingtry
statements have been executed. - Si la función contenedora no es una función asincrónica, el control se devuelve al autor de la llamada de la función contenedora junto con el valor del resultado, si existe.If the containing function is not an async function, control is returned to the caller of the containing function along with the result value, if any.
- Si la función contenedora es una función asincrónica, el control se devuelve al llamador actual y el valor del resultado, si existe, se registra en la tarea devuelta tal y como se describe en (interfaces del enumerador).If the containing function is an async function, control is returned to the current caller, and the result value, if any, is recorded in the return task as described in (Enumerator interfaces).
Dado return
que una instrucción transfiere el control incondicionalmente a otra parte, el punto final de una return
instrucción nunca es accesible.Because a return
statement unconditionally transfers control elsewhere, the end point of a return
statement is never reachable.
La instrucción throwThe throw statement
La instrucción throw
genera una excepción.The throw
statement throws an exception.
throw_statement
: 'throw' expression? ';'
;
Una throw
instrucción con una expresión inicia el valor generado al evaluar la expresión.A throw
statement with an expression throws the value produced by evaluating the expression. La expresión debe indicar un valor del tipo de clase System.Exception
, de un tipo de clase que se deriva de System.Exception
o de un tipo de parámetro de tipo que tiene System.Exception
(o una subclase de ella) como su clase base efectiva.The expression must denote a value of the class type System.Exception
, of a class type that derives from System.Exception
or of a type parameter type that has System.Exception
(or a subclass thereof) as its effective base class. Si la evaluación de la expresión produce null
, System.NullReferenceException
se produce una excepción en su lugar.If evaluation of the expression produces null
, a System.NullReferenceException
is thrown instead.
Una throw
instrucción sin expresión solo se puede usar en un catch
bloque, en cuyo caso la instrucción vuelve a iniciar la excepción que está controlando actualmente ese catch
bloque.A throw
statement with no expression can be used only in a catch
block, in which case that statement re-throws the exception that is currently being handled by that catch
block.
Dado throw
que una instrucción transfiere el control incondicionalmente a otra parte, el punto final de una throw
instrucción nunca es accesible.Because a throw
statement unconditionally transfers control elsewhere, the end point of a throw
statement is never reachable.
Cuando se produce una excepción, el control se transfiere a la primera catch
cláusula de una instrucción de inclusión try
que puede controlar la excepción.When an exception is thrown, control is transferred to the first catch
clause in an enclosing try
statement that can handle the exception. El proceso que tiene lugar desde el punto de la excepción que se está iniciando hasta el punto de transferir el control a un controlador de excepciones adecuado se conoce como *propagación de excepciones _.The process that takes place from the point of the exception being thrown to the point of transferring control to a suitable exception handler is known as *exception propagation _. La propagación de una excepción consiste en evaluar repetidamente los siguientes pasos hasta que catch
se encuentre una cláusula que coincida con la excepción.Propagation of an exception consists of repeatedly evaluating the following steps until a catch
clause that matches the exception is found. En esta descripción, el punto _ Throw* es inicialmente la ubicación en la que se produce la excepción.In this description, the _ throw point* is initially the location at which the exception is thrown.
En el miembro de función actual,
try
se examina cada instrucción que incluye el punto de inicio.In the current function member, eachtry
statement that encloses the throw point is examined. Para cada instrucciónS
, empezando por la instrucción más internatry
y finalizando con latry
instrucción externa, se evalúan los pasos siguientes:For each statementS
, starting with the innermosttry
statement and ending with the outermosttry
statement, the following steps are evaluated:Si el
try
bloque de incluyeS
el punto de inicio y si S tiene una o máscatch
cláusulas, lascatch
cláusulas se examinan en orden de aparición para encontrar un controlador adecuado para la excepción, de acuerdo con las reglas especificadas en la sección instrucción try.If thetry
block ofS
encloses the throw point and if S has one or morecatch
clauses, thecatch
clauses are examined in order of appearance to locate a suitable handler for the exception, according to the rules specified in Section The try statement. Sicatch
se encuentra una cláusula coincidente, la propagación de excepciones se completa mediante la transferencia del control al bloque de esacatch
cláusula.If a matchingcatch
clause is located, the exception propagation is completed by transferring control to the block of thatcatch
clause.De lo contrario, si el
try
bloque o uncatch
bloque de incluyeS
el punto de inicio y siS
tiene unfinally
bloque, el control se transfiere alfinally
bloque.Otherwise, if thetry
block or acatch
block ofS
encloses the throw point and ifS
has afinally
block, control is transferred to thefinally
block. Si elfinally
bloque produce otra excepción, finaliza el procesamiento de la excepción actual.If thefinally
block throws another exception, processing of the current exception is terminated. De lo contrario, cuando el control alcanza el punto final delfinally
bloque, continúa el procesamiento de la excepción actual.Otherwise, when control reaches the end point of thefinally
block, processing of the current exception is continued.
Si no se encuentra un controlador de excepciones en la invocación de función actual, se termina la invocación de la función y se produce uno de los siguientes casos:If an exception handler was not located in the current function invocation, the function invocation is terminated, and one of the following occurs:
Si la función actual no es asincrónica, los pasos anteriores se repiten para el llamador de la función con un punto de inicio correspondiente a la instrucción de la que se invocó el miembro de función.If the current function is non-async, the steps above are repeated for the caller of the function with a throw point corresponding to the statement from which the function member was invoked.
Si la función actual es asincrónica y devuelve la tarea, la excepción se registra en la tarea devuelta, que se coloca en un estado de error o cancelado, tal y como se describe en interfaces de enumerador.If the current function is async and task-returning, the exception is recorded in the return task, which is put into a faulted or cancelled state as described in Enumerator interfaces.
Si la función actual es asincrónica y devuelve void, el contexto de sincronización del subproceso actual se notifica como se describe en interfaces enumerables.If the current function is async and void-returning, the synchronization context of the current thread is notified as described in Enumerable interfaces.
Si el procesamiento de excepciones finaliza todas las invocaciones de miembros de función en el subproceso actual, lo que indica que el subproceso no tiene ningún controlador para la excepción, el subproceso se termina.If the exception processing terminates all function member invocations in the current thread, indicating that the thread has no handler for the exception, then the thread is itself terminated. El impacto de dicha terminación está definido por la implementación.The impact of such termination is implementation-defined.
Instrucción tryThe try statement
La try
instrucción proporciona un mecanismo para detectar las excepciones que se producen durante la ejecución de un bloque.The try
statement provides a mechanism for catching exceptions that occur during execution of a block. Además, la try
instrucción proporciona la capacidad de especificar un bloque de código que siempre se ejecuta cuando el control sale de la try
instrucción.Furthermore, the try
statement provides the ability to specify a block of code that is always executed when control leaves the try
statement.
try_statement
: 'try' block catch_clause+
| 'try' block finally_clause
| 'try' block catch_clause+ finally_clause
;
catch_clause
: 'catch' exception_specifier? exception_filter? block
;
exception_specifier
: '(' type identifier? ')'
;
exception_filter
: 'when' '(' expression ')'
;
finally_clause
: 'finally' block
;
Hay tres formas posibles de try
instrucciones:There are three possible forms of try
statements:
- Un
try
bloque seguido de uno o varioscatch
bloques.Atry
block followed by one or morecatch
blocks. - Un
try
bloque seguido de unfinally
bloque.Atry
block followed by afinally
block. - Un
try
bloque seguido de uno o varioscatch
bloques seguidos de unfinally
bloque.Atry
block followed by one or morecatch
blocks followed by afinally
block.
Cuando una catch
cláusula especifica un exception_specifier, el tipo debe ser System.Exception
, un tipo que se deriva de System.Exception
o un tipo de parámetro de tipo que tiene System.Exception
(o una subclase de ella) como su clase base efectiva.When a catch
clause specifies an exception_specifier, the type must be System.Exception
, a type that derives from System.Exception
or a type parameter type that has System.Exception
(or a subclass thereof) as its effective base class.
Cuando una catch
cláusula especifica un exception_specifier con un identificador, se declara una variable de excepción* _ del nombre y tipo especificados.When a catch
clause specifies both an exception_specifier with an identifier, an *exception variable _ of the given name and type is declared. La variable de excepción corresponde a una variable local con un ámbito que se extiende por encima de la catch
cláusula.The exception variable corresponds to a local variable with a scope that extends over the catch
clause. Durante la ejecución del _exception_filter * y el bloque, la variable de excepción representa la excepción que se está controlando actualmente.During execution of the _exception_filter* and block, the exception variable represents the exception currently being handled. A efectos de la comprobación de asignación definitiva, la variable de excepción se considera asignada definitivamente en todo el ámbito.For purposes of definite assignment checking, the exception variable is considered definitely assigned in its entire scope.
A menos que una catch
cláusula incluya un nombre de variable de excepción, no es posible tener acceso al objeto de excepción en el filtro y catch
bloque.Unless a catch
clause includes an exception variable name, it is impossible to access the exception object in the filter and catch
block.
Una catch
cláusula que no especifica un exception_specifier se denomina catch
cláusula general.A catch
clause that does not specify an exception_specifier is called a general catch
clause.
Algunos lenguajes de programación pueden admitir excepciones que no pueden representarse como un objeto derivado de System.Exception
, aunque estas excepciones nunca podrían generarse en el código de C#.Some programming languages may support exceptions that are not representable as an object derived from System.Exception
, although such exceptions could never be generated by C# code. catch
Se puede usar una cláusula general para detectar tales excepciones.A general catch
clause may be used to catch such exceptions. Por lo tanto, una catch
cláusula general es semánticamente diferente de una que especifica el tipo System.Exception
, en que la primera también puede detectar excepciones de otros lenguajes.Thus, a general catch
clause is semantically different from one that specifies the type System.Exception
, in that the former may also catch exceptions from other languages.
Para buscar un controlador de una excepción, las catch
cláusulas se examinan en orden léxico.In order to locate a handler for an exception, catch
clauses are examined in lexical order. Si una catch
cláusula especifica un tipo pero no un filtro de excepción, se trata de un error en tiempo de compilación para una catch
cláusula posterior en la misma try
instrucción para especificar un tipo que sea igual o derivado de ese tipo.If a catch
clause specifies a type but no exception filter, it is a compile-time error for a later catch
clause in the same try
statement to specify a type that is the same as, or is derived from, that type. Si una catch
cláusula no especifica ningún tipo y no hay ningún filtro, debe ser la última catch
cláusula para esa try
instrucción.If a catch
clause specifies no type and no filter, it must be the last catch
clause for that try
statement.
Dentro de un catch
bloque, throw
se puede usar una instrucción (instrucción throw) sin expresión para volver a producir la excepción detectada por el catch
bloque.Within a catch
block, a throw
statement (The throw statement) with no expression can be used to re-throw the exception that was caught by the catch
block. Las asignaciones a una variable de excepción no modifican la excepción que se vuelve a iniciar.Assignments to an exception variable do not alter the exception that is re-thrown.
En el ejemploIn the example
using System;
class Test
{
static void F() {
try {
G();
}
catch (Exception e) {
Console.WriteLine("Exception in F: " + e.Message);
e = new Exception("F");
throw; // re-throw
}
}
static void G() {
throw new Exception("G");
}
static void Main() {
try {
F();
}
catch (Exception e) {
Console.WriteLine("Exception in Main: " + e.Message);
}
}
}
el método F
detecta una excepción, escribe información de diagnóstico en la consola, modifica la variable de excepción y vuelve a producir la excepción.the method F
catches an exception, writes some diagnostic information to the console, alters the exception variable, and re-throws the exception. La excepción que se vuelve a producir es la excepción original, por lo que la salida generada es:The exception that is re-thrown is the original exception, so the output produced is:
Exception in F: G
Exception in Main: G
Si se produjo el primer bloque catch e
en lugar de volver a producir la excepción actual, la salida generada sería la siguiente:If the first catch block had thrown e
instead of rethrowing the current exception, the output produced would be as follows:
Exception in F: G
Exception in Main: F
Es un error en tiempo de compilación para una break
continue
instrucción, o goto
para transferir el control fuera de un finally
bloque.It is a compile-time error for a break
, continue
, or goto
statement to transfer control out of a finally
block. Cuando una break
continue
instrucción, o goto
aparece en un finally
bloque, el destino de la instrucción debe estar dentro del mismo finally
bloque o, de lo contrario, se produce un error en tiempo de compilación.When a break
, continue
, or goto
statement occurs in a finally
block, the target of the statement must be within the same finally
block, or otherwise a compile-time error occurs.
Se trata de un error en tiempo de compilación para return
que una instrucción se produzca en un finally
bloque.It is a compile-time error for a return
statement to occur in a finally
block.
Una try
instrucción se ejecuta de la siguiente manera:A try
statement is executed as follows:
El control se transfiere al
try
bloque.Control is transferred to thetry
block.When y si el control alcanza el punto final del
try
bloque:When and if control reaches the end point of thetry
block:- Si la
try
instrucción tiene unfinally
bloque,finally
se ejecuta el bloque.If thetry
statement has afinally
block, thefinally
block is executed. - El control se transfiere al punto final de la
try
instrucción.Control is transferred to the end point of thetry
statement.
- Si la
Si una excepción se propaga a la
try
instrucción durante la ejecución deltry
bloque:If an exception is propagated to thetry
statement during execution of thetry
block:- Las
catch
cláusulas, si las hay, se examinan en orden de aparición para encontrar un controlador adecuado para la excepción.Thecatch
clauses, if any, are examined in order of appearance to locate a suitable handler for the exception. Si unacatch
cláusula no especifica un tipo, o especifica el tipo de excepción o un tipo base del tipo de excepción:If acatch
clause does not specify a type, or specifies the exception type or a base type of the exception type:- Si la
catch
cláusula declara una variable de excepción, el objeto de excepción se asigna a la variable de excepción.If thecatch
clause declares an exception variable, the exception object is assigned to the exception variable. - Si la
catch
cláusula declara un filtro de excepción, se evalúa el filtro.If thecatch
clause declares an exception filter, the filter is evaluated. Si se evalúa comofalse
, la cláusula catch no es una coincidencia y la búsqueda continúa a travéscatch
de las cláusulas posteriores de un controlador adecuado.If it evaluates tofalse
, the catch clause is not a match, and the search continues through any subsequentcatch
clauses for a suitable handler. - De lo contrario, la
catch
cláusula se considera una coincidencia y el control se transfiere alcatch
bloque coincidente.Otherwise, thecatch
clause is considered a match, and control is transferred to the matchingcatch
block. - When y si el control alcanza el punto final del
catch
bloque:When and if control reaches the end point of thecatch
block:- Si la
try
instrucción tiene unfinally
bloque,finally
se ejecuta el bloque.If thetry
statement has afinally
block, thefinally
block is executed. - El control se transfiere al punto final de la
try
instrucción.Control is transferred to the end point of thetry
statement.
- Si la
- Si una excepción se propaga a la
try
instrucción durante la ejecución delcatch
bloque:If an exception is propagated to thetry
statement during execution of thecatch
block:- Si la
try
instrucción tiene unfinally
bloque,finally
se ejecuta el bloque.If thetry
statement has afinally
block, thefinally
block is executed. - La excepción se propaga a la siguiente instrucción de inclusión
try
.The exception is propagated to the next enclosingtry
statement.
- Si la
- Si la
- Si la
try
instrucción no tienecatch
cláusulas o si ningunacatch
cláusula coincide con la excepción:If thetry
statement has nocatch
clauses or if nocatch
clause matches the exception:- Si la
try
instrucción tiene unfinally
bloque,finally
se ejecuta el bloque.If thetry
statement has afinally
block, thefinally
block is executed. - La excepción se propaga a la siguiente instrucción de inclusión
try
.The exception is propagated to the next enclosingtry
statement.
- Si la
- Las
Las instrucciones de un finally
bloque siempre se ejecutan cuando el control sale de una try
instrucción.The statements of a finally
block are always executed when control leaves a try
statement. Esto es cierto si la transferencia de control se produce como resultado de la ejecución normal, como resultado de la ejecución de una break
continue
instrucción,, goto
o return
, o como resultado de propagar una excepción fuera de la try
instrucción.This is true whether the control transfer occurs as a result of normal execution, as a result of executing a break
, continue
, goto
, or return
statement, or as a result of propagating an exception out of the try
statement.
Si se produce una excepción durante la ejecución de un finally
bloque y no se detecta en el mismo bloque Finally, la excepción se propaga a la siguiente instrucción envolvente try
.If an exception is thrown during execution of a finally
block, and is not caught within the same finally block, the exception is propagated to the next enclosing try
statement. Si hay otra excepción en el proceso de propagación, se perderá esa excepción.If another exception was in the process of being propagated, that exception is lost. El proceso de propagación de una excepción se describe con más detalle en la descripción de la throw
instrucción (la instrucción throw).The process of propagating an exception is discussed further in the description of the throw
statement (The throw statement).
El try
bloque de una try
instrucción es accesible si la try
instrucción es accesible.The try
block of a try
statement is reachable if the try
statement is reachable.
catch
Se puede tener acceso a un bloque de una try
instrucción si la try
instrucción es accesible.A catch
block of a try
statement is reachable if the try
statement is reachable.
El finally
bloque de una try
instrucción es accesible si la try
instrucción es accesible.The finally
block of a try
statement is reachable if the try
statement is reachable.
El punto final de una try
instrucción es accesible si se cumplen las dos condiciones siguientes:The end point of a try
statement is reachable if both of the following are true:
- El punto final del
try
bloque es accesible ocatch
se puede tener acceso al punto final de al menos un bloque.The end point of thetry
block is reachable or the end point of at least onecatch
block is reachable. - Si
finally
hay un bloque,finally
se puede tener acceso al punto final del bloque.If afinally
block is present, the end point of thefinally
block is reachable.
Instrucciones checked y uncheckedThe checked and unchecked statements
Las checked
unchecked
instrucciones y se utilizan para controlar el contexto de comprobación de desbordamiento para conversiones y operaciones aritméticas de tipo entero.The checked
and unchecked
statements are used to control the overflow checking context for integral-type arithmetic operations and conversions.
checked_statement
: 'checked' block
;
unchecked_statement
: 'unchecked' block
;
La checked
instrucción hace que todas las expresiones del bloque se evalúen en un contexto comprobado, y la unchecked
instrucción hace que todas las expresiones del bloque se evalúen en un contexto no comprobado.The checked
statement causes all expressions in the block to be evaluated in a checked context, and the unchecked
statement causes all expressions in the block to be evaluated in an unchecked context.
Las checked
unchecked
instrucciones y son exactamente equivalentes a checked
los unchecked
operadores y (los operadores Checked y unchecked), salvo que operan en bloques en lugar de en expresiones.The checked
and unchecked
statements are precisely equivalent to the checked
and unchecked
operators (The checked and unchecked operators), except that they operate on blocks instead of expressions.
lock (instrucción)The lock statement
La lock
instrucción obtiene el bloqueo de exclusión mutua para un objeto determinado, ejecuta una instrucción y, a continuación, libera el bloqueo.The lock
statement obtains the mutual-exclusion lock for a given object, executes a statement, and then releases the lock.
lock_statement
: 'lock' '(' expression ')' embedded_statement
;
La expresión de una lock
instrucción debe indicar un valor de un tipo conocido como reference_type.The expression of a lock
statement must denote a value of a type known to be a reference_type. No se realiza ninguna conversión boxing implícita (conversiones boxing) en la expresión de una lock
instrucción y, por lo tanto, es un error en tiempo de compilación para que la expresión denote un valor de un value_type.No implicit boxing conversion (Boxing conversions) is ever performed for the expression of a lock
statement, and thus it is a compile-time error for the expression to denote a value of a value_type.
Una lock
instrucción con el formatoA lock
statement of the form
lock (x) ...
donde x
es una expresión de un reference_type, es precisamente equivalente awhere x
is an expression of a reference_type, is precisely equivalent to
bool __lockWasTaken = false;
try {
System.Threading.Monitor.Enter(x, ref __lockWasTaken);
...
}
finally {
if (__lockWasTaken) System.Threading.Monitor.Exit(x);
}
salvo que x
solo se evalúa una vez.except that x
is only evaluated once.
Mientras se mantiene un bloqueo de exclusión mutua, el código que se ejecuta en el mismo subproceso de ejecución también puede obtener y liberar el bloqueo.While a mutual-exclusion lock is held, code executing in the same execution thread can also obtain and release the lock. Sin embargo, el código que se ejecuta en otros subprocesos no obtiene el bloqueo hasta que se libera el bloqueo.However, code executing in other threads is blocked from obtaining the lock until the lock is released.
System.Type
No se recomienda el bloqueo de objetos para sincronizar el acceso a los datos estáticos.Locking System.Type
objects in order to synchronize access to static data is not recommended. Otro código podría bloquearse en el mismo tipo, lo que puede provocar un interbloqueo.Other code might lock on the same type, which can result in deadlock. Un mejor enfoque es sincronizar el acceso a los datos estáticos bloqueando un objeto estático privado.A better approach is to synchronize access to static data by locking a private static object. Por ejemplo:For example:
class Cache
{
private static readonly object synchronizationObject = new object();
public static void Add(object x) {
lock (Cache.synchronizationObject) {
...
}
}
public static void Remove(object x) {
lock (Cache.synchronizationObject) {
...
}
}
}
La instrucción usingThe using statement
La using
instrucción obtiene uno o más recursos, ejecuta una instrucción y, a continuación, desecha el recurso.The using
statement obtains one or more resources, executes a statement, and then disposes of the resource.
using_statement
: 'using' '(' resource_acquisition ')' embedded_statement
;
resource_acquisition
: local_variable_declaration
| expression
;
Un recurso es una clase o estructura que implementa System.IDisposable
, que incluye un único método sin parámetros denominado Dispose
.A resource is a class or struct that implements System.IDisposable
, which includes a single parameterless method named Dispose
. El código que usa un recurso puede llamar Dispose
a para indicar que el recurso ya no es necesario.Code that is using a resource can call Dispose
to indicate that the resource is no longer needed. Si Dispose
no se llama a, la eliminación automática se produce finalmente como consecuencia de la recolección de elementos no utilizados.If Dispose
is not called, then automatic disposal eventually occurs as a consequence of garbage collection.
Si el formato de resource_acquisition es local_variable_declaration , el tipo de la local_variable_declaration debe ser dynamic
o un tipo que se pueda convertir implícitamente en System.IDisposable
.If the form of resource_acquisition is local_variable_declaration then the type of the local_variable_declaration must be either dynamic
or a type that can be implicitly converted to System.IDisposable
. Si el formato de resource_acquisition es Expression , esta expresión debe poder convertirse implícitamente en System.IDisposable
.If the form of resource_acquisition is expression then this expression must be implicitly convertible to System.IDisposable
.
Las variables locales declaradas en un resource_acquisition son de solo lectura y deben incluir un inicializador.Local variables declared in a resource_acquisition are read-only, and must include an initializer. Se produce un error en tiempo de compilación si la instrucción incrustada intenta modificar estas variables locales (a través de la asignación o los ++
--
operadores y), tomar la dirección de ellas o pasarlas como ref
out
parámetros o.A compile-time error occurs if the embedded statement attempts to modify these local variables (via assignment or the ++
and --
operators) , take the address of them, or pass them as ref
or out
parameters.
Una using
instrucción se traduce en tres partes: adquisición, uso y eliminación.A using
statement is translated into three parts: acquisition, usage, and disposal. El uso del recurso se adjunta implícitamente en una try
instrucción que incluye una finally
cláusula.Usage of the resource is implicitly enclosed in a try
statement that includes a finally
clause. Esta finally
cláusula desecha el recurso.This finally
clause disposes of the resource. Si null
se adquiere un recurso, no se realiza ninguna llamada a Dispose
y no se produce ninguna excepción.If a null
resource is acquired, then no call to Dispose
is made, and no exception is thrown. Si el recurso es de tipo dynamic
, se convierte dinámicamente a través de una conversión dinámica implícita (conversiones dinámicas implícitas) en IDisposable
durante la adquisición para asegurarse de que la conversión se realiza correctamente antes del uso y la eliminación.If the resource is of type dynamic
it is dynamically converted through an implicit dynamic conversion (Implicit dynamic conversions) to IDisposable
during acquisition in order to ensure that the conversion is successful before the usage and disposal.
Una using
instrucción con el formatoA using
statement of the form
using (ResourceType resource = expression) statement
corresponde a una de las tres expansiones posibles.corresponds to one of three possible expansions. Cuando ResourceType
es un tipo de valor que no acepta valores NULL, la expansión esWhen ResourceType
is a non-nullable value type, the expansion is
{
ResourceType resource = expression;
try {
statement;
}
finally {
((IDisposable)resource).Dispose();
}
}
De lo contrario, cuando ResourceType
es un tipo de valor que acepta valores NULL o un tipo de referencia distinto de dynamic
, la expansión esOtherwise, when ResourceType
is a nullable value type or a reference type other than dynamic
, the expansion is
{
ResourceType resource = expression;
try {
statement;
}
finally {
if (resource != null) ((IDisposable)resource).Dispose();
}
}
De lo contrario, cuando ResourceType
es dynamic
, la expansión esOtherwise, when ResourceType
is dynamic
, the expansion is
{
ResourceType resource = expression;
IDisposable d = (IDisposable)resource;
try {
statement;
}
finally {
if (d != null) d.Dispose();
}
}
En cualquier expansión, la resource
variable es de solo lectura en la instrucción incrustada, y d
no se puede obtener acceso a la variable en la instrucción incrustada y no es visible para ella.In either expansion, the resource
variable is read-only in the embedded statement, and the d
variable is inaccessible in, and invisible to, the embedded statement.
Una implementación puede implementar una instrucción using determinada de forma diferente, por ejemplo, por motivos de rendimiento, siempre que el comportamiento sea coherente con la expansión anterior.An implementation is permitted to implement a given using-statement differently, e.g. for performance reasons, as long as the behavior is consistent with the above expansion.
Una using
instrucción con el formatoA using
statement of the form
using (expression) statement
tiene las mismas tres expansiones posibles.has the same three possible expansions. En este caso ResourceType
, es implícitamente el tipo en tiempo de compilación de expression
, si tiene uno.In this case ResourceType
is implicitly the compile-time type of the expression
, if it has one. En caso contrario, la IDisposable
propia interfaz se utiliza como ResourceType
.Otherwise the interface IDisposable
itself is used as the ResourceType
. resource
No se puede obtener acceso a la variable en y no es visible para la instrucción incrustada.The resource
variable is inaccessible in, and invisible to, the embedded statement.
Cuando un resource_acquisition adopta la forma de un local_variable_declaration, es posible adquirir varios recursos de un tipo determinado.When a resource_acquisition takes the form of a local_variable_declaration, it is possible to acquire multiple resources of a given type. Una using
instrucción con el formatoA using
statement of the form
using (ResourceType r1 = e1, r2 = e2, ..., rN = eN) statement
es exactamente equivalente a una secuencia de instrucciones anidadas using
:is precisely equivalent to a sequence of nested using
statements:
using (ResourceType r1 = e1)
using (ResourceType r2 = e2)
...
using (ResourceType rN = eN)
statement
En el ejemplo siguiente se crea un archivo denominado log.txt
y se escriben dos líneas de texto en el archivo.The example below creates a file named log.txt
and writes two lines of text to the file. A continuación, el ejemplo abre el mismo archivo para leer y copia las líneas de texto contenidas en la consola.The example then opens that same file for reading and copies the contained lines of text to the console.
using System;
using System.IO;
class Test
{
static void Main() {
using (TextWriter w = File.CreateText("log.txt")) {
w.WriteLine("This is line one");
w.WriteLine("This is line two");
}
using (TextReader r = File.OpenText("log.txt")) {
string s;
while ((s = r.ReadLine()) != null) {
Console.WriteLine(s);
}
}
}
}
Dado que TextWriter
las TextReader
clases y implementan la IDisposable
interfaz, el ejemplo puede utilizar using
instrucciones para asegurarse de que el archivo subyacente está cerrado correctamente después de las operaciones de escritura o lectura.Since the TextWriter
and TextReader
classes implement the IDisposable
interface, the example can use using
statements to ensure that the underlying file is properly closed following the write or read operations.
Yield (instrucción)The yield statement
La yield
instrucción se usa en un bloque de iteradores (bloques) para obtener un valor para el objeto enumerador (objetos enumerador) o el objeto enumerable (objetos enumerables) de un iterador o para señalar el final de la iteración.The yield
statement is used in an iterator block (Blocks) to yield a value to the enumerator object (Enumerator objects) or enumerable object (Enumerable objects) of an iterator or to signal the end of the iteration.
yield_statement
: 'yield' 'return' expression ';'
| 'yield' 'break' ';'
;
yield
no es una palabra reservada; tiene un significado especial solo cuando se usa inmediatamente antes de una return
break
palabra clave o.yield
is not a reserved word; it has special meaning only when used immediately before a return
or break
keyword. En otros contextos, yield
se puede usar como identificador.In other contexts, yield
can be used as an identifier.
Hay varias restricciones sobre dónde yield
puede aparecer una instrucción, tal y como se describe a continuación.There are several restrictions on where a yield
statement can appear, as described in the following.
- Es un error en tiempo de compilación que una
yield
instrucción (de cualquier forma) aparezca fuera de un method_body, operator_body o accessor_bodyIt is a compile-time error for ayield
statement (of either form) to appear outside a method_body, operator_body or accessor_body - Es un error en tiempo de compilación para una
yield
instrucción (de cualquier forma) que aparezca dentro de una función anónima.It is a compile-time error for ayield
statement (of either form) to appear inside an anonymous function. - Es un error en tiempo de compilación para una
yield
instrucción (de cualquier forma) que aparezca en lafinally
cláusula de unatry
instrucción.It is a compile-time error for ayield
statement (of either form) to appear in thefinally
clause of atry
statement. - Se trata de un error en tiempo de compilación para
yield return
que una instrucción aparezca en cualquier parte de unatry
instrucción que contengacatch
cláusulas.It is a compile-time error for ayield return
statement to appear anywhere in atry
statement that contains anycatch
clauses.
En el ejemplo siguiente se muestran algunos usos válidos y no válidos de las yield
instrucciones.The following example shows some valid and invalid uses of yield
statements.
delegate IEnumerable<int> D();
IEnumerator<int> GetEnumerator() {
try {
yield return 1; // Ok
yield break; // Ok
}
finally {
yield return 2; // Error, yield in finally
yield break; // Error, yield in finally
}
try {
yield return 3; // Error, yield return in try...catch
yield break; // Ok
}
catch {
yield return 4; // Error, yield return in try...catch
yield break; // Ok
}
D d = delegate {
yield return 5; // Error, yield in an anonymous function
};
}
int MyMethod() {
yield return 1; // Error, wrong return type for an iterator block
}
Debe existir una conversión implícita (conversiones implícitas) del tipo de la expresión en la yield return
instrucción al tipo yield (yield Type) del iterador.An implicit conversion (Implicit conversions) must exist from the type of the expression in the yield return
statement to the yield type (Yield type) of the iterator.
Una yield return
instrucción se ejecuta de la siguiente manera:A yield return
statement is executed as follows:
- La expresión dada en la instrucción se evalúa, se convierte implícitamente al tipo Yield y se asigna a la
Current
propiedad del objeto enumerador.The expression given in the statement is evaluated, implicitly converted to the yield type, and assigned to theCurrent
property of the enumerator object. - La ejecución del bloque de iterador está suspendida.Execution of the iterator block is suspended. Si la
yield return
instrucción está dentro de uno o mástry
bloques, losfinally
bloques asociados no se ejecutan en este momento.If theyield return
statement is within one or moretry
blocks, the associatedfinally
blocks are not executed at this time. - El
MoveNext
método del objeto de enumerador vuelvetrue
a su llamador, lo que indica que el objeto de enumerador avanzó correctamente al siguiente elemento.TheMoveNext
method of the enumerator object returnstrue
to its caller, indicating that the enumerator object successfully advanced to the next item.
La siguiente llamada al método del objeto de enumerador MoveNext
reanuda la ejecución del bloque de iterador desde donde se suspendió por última vez.The next call to the enumerator object's MoveNext
method resumes execution of the iterator block from where it was last suspended.
Una yield break
instrucción se ejecuta de la siguiente manera:A yield break
statement is executed as follows:
- Si la
yield break
instrucción está delimitada por uno o mástry
bloques confinally
bloques asociados, el control se transfiere inicialmente alfinally
bloque de latry
instrucción más interna.If theyield break
statement is enclosed by one or moretry
blocks with associatedfinally
blocks, control is initially transferred to thefinally
block of the innermosttry
statement. Cuando y si el control alcanza el punto final de unfinally
bloque, el control se transfiere alfinally
bloque de la siguiente instrucción de inclusióntry
.When and if control reaches the end point of afinally
block, control is transferred to thefinally
block of the next enclosingtry
statement. Este proceso se repite hasta quefinally
se hayan ejecutado los bloques de todas las instrucciones envolventestry
.This process is repeated until thefinally
blocks of all enclosingtry
statements have been executed. - El control se devuelve al llamador del bloque de iteradores.Control is returned to the caller of the iterator block. Este es el
MoveNext
método o elDispose
método del objeto de enumerador.This is either theMoveNext
method orDispose
method of the enumerator object.
Dado yield break
que una instrucción transfiere el control incondicionalmente a otra parte, el punto final de una yield break
instrucción nunca es accesible.Because a yield break
statement unconditionally transfers control elsewhere, the end point of a yield break
statement is never reachable.