Istruzioni Jump - break
, continue
, return
e goto
Le istruzioni jump trasferisce in modo incondizionato il controllo. L'istruzionebreak
termina l'istruzione o switch
l'istruzione di iterazione più vicina. L'istruzionecontinue
avvia una nuova iterazione dell'istruzione iterazione più vicina. L'istruzionereturn
termina l'esecuzione della funzione in cui viene visualizzata e restituisce il controllo al chiamante. L'istruzionegoto
trasferisce il controllo a un'istruzione contrassegnata da un'etichetta.
Per informazioni sull'istruzione che genera un'eccezione e trasferisce in modo incondizionato anche il controllo, vedere La sezione Istruzione throw
dell'articolo throw
Istruzioni di gestione delle eccezioni.
Istruzione break
L'istruzione break
termina l'istruzione più vicina che racchiude l'istruzione di iterazione, ovvero , for
foreach
while
o do
ciclo.switch
L'istruzione break
trasferisce il controllo all'istruzione che segue l'istruzione terminata, se presente.
int[] numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
foreach (int number in numbers)
{
if (number == 3)
{
break;
}
Console.Write($"{number} ");
}
Console.WriteLine();
Console.WriteLine("End of the example.");
// Output:
// 0 1 2
// End of the example.
Nei cicli annidati l'istruzione break
termina solo il ciclo più interno che lo contiene, come illustrato nell'esempio seguente:
for (int outer = 0; outer < 5; outer++)
{
for (int inner = 0; inner < 5; inner++)
{
if (inner > outer)
{
break;
}
Console.Write($"{inner} ");
}
Console.WriteLine();
}
// Output:
// 0
// 0 1
// 0 1 2
// 0 1 2 3
// 0 1 2 3 4
Quando si usa l'istruzione switch
all'interno di un ciclo, un'istruzione break
alla fine di una sezione switch trasferisce il controllo solo all'esterno dell'istruzione switch
. Il ciclo che contiene l'istruzione non è interessato, come illustrato nell'esempio switch
seguente:
double[] measurements = { -4, 5, 30, double.NaN };
foreach (double measurement in measurements)
{
switch (measurement)
{
case < 0.0:
Console.WriteLine($"Measured value is {measurement}; too low.");
break;
case > 15.0:
Console.WriteLine($"Measured value is {measurement}; too high.");
break;
case double.NaN:
Console.WriteLine("Failed measurement.");
break;
default:
Console.WriteLine($"Measured value is {measurement}.");
break;
}
}
// Output:
// Measured value is -4; too low.
// Measured value is 5.
// Measured value is 30; too high.
// Failed measurement.
Istruzione continue
L'istruzione continue
avvia una nuova iterazione dell'istruzione iterazione più vicina, ovvero , , foreach
while
, o do
ciclo, for
come illustrato nell'esempio seguente:
for (int i = 0; i < 5; i++)
{
Console.Write($"Iteration {i}: ");
if (i < 3)
{
Console.WriteLine("skip");
continue;
}
Console.WriteLine("done");
}
// Output:
// Iteration 0: skip
// Iteration 1: skip
// Iteration 2: skip
// Iteration 3: done
// Iteration 4: done
Istruzione return
L'istruzione return
termina l'esecuzione della funzione in cui viene visualizzata e restituisce il controllo e il risultato della funzione, se presente, al chiamante.
Se un membro della funzione non calcola un valore, usare l'istruzione senza espressione, come illustrato nell'esempio return
seguente:
Console.WriteLine("First call:");
DisplayIfNecessary(6);
Console.WriteLine("Second call:");
DisplayIfNecessary(5);
void DisplayIfNecessary(int number)
{
if (number % 2 == 0)
{
return;
}
Console.WriteLine(number);
}
// Output:
// First call:
// Second call:
// 5
Come illustrato nell'esempio precedente, in genere si usa l'istruzione return
senza espressione per terminare un membro della funzione in anticipo. Se un membro della funzione non contiene l'istruzione, termina dopo l'esecuzione dell'ultima return
istruzione.
Se un membro della funzione calcola un valore, usare l'istruzione con un'espressione, come illustrato nell'esempio return
seguente:
double surfaceArea = CalculateCylinderSurfaceArea(1, 1);
Console.WriteLine($"{surfaceArea:F2}"); // output: 12.57
double CalculateCylinderSurfaceArea(double baseRadius, double height)
{
double baseArea = Math.PI * baseRadius * baseRadius;
double sideArea = 2 * Math.PI * baseRadius * height;
return 2 * baseArea + sideArea;
}
Quando l'istruzione ha un'espressione, tale return
espressione deve essere convertibile in modo implicito nel tipo restituito di un membro di funzione a meno che non sia asincrona. L'espressione restituita da una async
funzione deve essere convertibile in modo implicito nell'argomento di tipo di Task<TResult> o ValueTask<TResult>, ovvero il tipo restituito della funzione. Se il tipo restituito di una async
funzione è Task o ValueTask, usare l'istruzione return
senza espressione.
Valori restituiti
Per impostazione predefinita, l'istruzione return
restituisce il valore di un'espressione. È possibile restituire un riferimento a una variabile. A tale scopo, usare l'istruzione con la parola chiave, come illustrato nell'esempio return
ref
seguente:
var xs = new int[] { 10, 20, 30, 40 };
ref int found = ref FindFirst(xs, s => s == 30);
found = 0;
Console.WriteLine(string.Join(" ", xs)); // output: 10 20 0 40
ref int FindFirst(int[] numbers, Func<int, bool> predicate)
{
for (int i = 0; i < numbers.Length; i++)
{
if (predicate(numbers[i]))
{
return ref numbers[i];
}
}
throw new InvalidOperationException("No element satisfies the given condition.");
}
I valori restituiti possono essere restituiti dal riferimento (ref
restituisce). Un valore restituito di riferimento consente a un metodo di restituire a un chiamante un riferimento a una variabile, invece di un valore. Il chiamante può quindi scegliere di trattare la variabile come se fosse stata restituita da un valore o un riferimento. Il chiamante può creare una nuova variabile che è un riferimento al valore restituito, denominato ref local. Un valore restituito di riferimento indica che un metodo restituisce un riferimento (o alias) a una variabile. L'ambito di tale variabile deve includere il metodo. La durata della variabile deve estendersi oltre la restituzione del controllo del metodo. Le modifiche effettuate dal chiamante al valore restituito del metodo vengono apportate alla variabile restituita dal metodo.
La dichiarazione che un metodo restituisce un valore restituito di riferimento indica che il metodo restituisce un alias a una variabile. La finalità di progettazione è spesso che la chiamata di codice accede alla variabile tramite l'alias, incluso per modificarla. I metodi restituiti da riferimento non possono avere il tipo void
restituito .
Il ref
valore restituito è un alias per un'altra variabile nell'ambito del metodo chiamato. È possibile interpretare qualsiasi uso del valore restituito ref come uso della variabile di cui effettua l'aliasing:
- Quando si assegna il relativo valore, si assegna un valore alla variabile che esegue l'alias.
- Quando si legge il valore, si legge il valore della variabile che alias.
- Se viene restituito in base al riferimento, viene restituito un alias alla stessa variabile.
- Se lo si passa a un altro metodo per riferimento, si passa un riferimento alla variabile che esegue l'alias.
- Quando si crea un alias locale ref, si crea un nuovo alias per la stessa variabile.
Una restituzione di riferimento deve essere ref_safe_to_escape al metodo chiamante. Ciò significa che:
- Il valore restituito deve avere una durata che si estende oltre l'esecuzione del metodo. In altre parole, non può essere una variabile locale nel metodo che lo restituisce. Può essere un'istanza o un campo statico di una classe oppure un argomento passato al metodo. Il tentativo di restituire una variabile locale genera un errore del compilatore CS8168, "Impossibile restituire 'obj' locale in base al riferimento perché non è un riferimento locale di riferimento".
- Il valore restituito non può essere il valore letterale
null
. Un metodo con una restituzione ref può restituire un alias a una variabile il cui valore è attualmente ilnull
valore (non valido) o un tipo di valore nullable per un tipo di valore. - Il valore restituito non può essere una costante, un membro di enumerazione, il valore restituito per valore da una proprietà o un metodo di o
class
struct
.
Inoltre, i valori restituiti di riferimento non sono consentiti nei metodi asincroni. Un metodo asincrono può restituire il controllo prima del termine dell'esecuzione, quando il valore restituito è ancora sconosciuto.
Un metodo che restituisce un valore restituito di riferimento deve:
- Includere la parola chiave ref davanti al tipo restituito.
- Ogni istruzione return nel corpo del metodo include la parola chiave ref davanti al nome dell'istanza restituita.
L'esempio seguente illustra un metodo che soddisfa le condizioni e restituisce un riferimento a un oggetto Person
denominato p
:
public ref Person GetContactInformation(string fname, string lname)
{
// ...method implementation...
return ref p;
}
Istruzione goto
L'istruzione goto
trasferisce il controllo a un'istruzione contrassegnata da un'etichetta, come illustrato nell'esempio seguente:
var matrices = new Dictionary<string, int[][]>
{
["A"] = new[]
{
new[] { 1, 2, 3, 4 },
new[] { 4, 3, 2, 1 }
},
["B"] = new[]
{
new[] { 5, 6, 7, 8 },
new[] { 8, 7, 6, 5 }
},
};
CheckMatrices(matrices, 4);
void CheckMatrices(Dictionary<string, int[][]> matrixLookup, int target)
{
foreach (var (key, matrix) in matrixLookup)
{
for (int row = 0; row < matrix.Length; row++)
{
for (int col = 0; col < matrix[row].Length; col++)
{
if (matrix[row][col] == target)
{
goto Found;
}
}
}
Console.WriteLine($"Not found {target} in matrix {key}.");
continue;
Found:
Console.WriteLine($"Found {target} in matrix {key}.");
}
}
// Output:
// Found 4 in matrix A.
// Not found 4 in matrix B.
Come illustrato nell'esempio precedente, è possibile usare l'istruzione goto
per uscire da un ciclo annidato.
Suggerimento
Quando si utilizzano cicli annidati, è consigliabile eseguire il refactoring di cicli separati in metodi separati. Ciò può portare a un codice più semplice e leggibile senza l'istruzione goto
.
È anche possibile usare l'istruzione nell'istruzione goto
per trasferire il controllo in una sezione switch con un'etichetta di maiuscole costanti, come illustrato nell'esempio switch
seguente:
using System;
public enum CoffeeChoice
{
Plain,
WithMilk,
WithIceCream,
}
public class GotoInSwitchExample
{
public static void Main()
{
Console.WriteLine(CalculatePrice(CoffeeChoice.Plain)); // output: 10.0
Console.WriteLine(CalculatePrice(CoffeeChoice.WithMilk)); // output: 15.0
Console.WriteLine(CalculatePrice(CoffeeChoice.WithIceCream)); // output: 17.0
}
private static decimal CalculatePrice(CoffeeChoice choice)
{
decimal price = 0;
switch (choice)
{
case CoffeeChoice.Plain:
price += 10.0m;
break;
case CoffeeChoice.WithMilk:
price += 5.0m;
goto case CoffeeChoice.Plain;
case CoffeeChoice.WithIceCream:
price += 7.0m;
goto case CoffeeChoice.Plain;
}
return price;
}
}
All'interno dell'istruzione switch
è anche possibile usare l'istruzione goto default;
per trasferire il controllo alla sezione switch con l'etichetta default
.
Se un'etichetta con il nome specificato non esiste nel membro della funzione corrente o se l'istruzione goto
non rientra nell'ambito dell'etichetta, si verifica un errore in fase di compilazione. Ovvero, non è possibile usare l'istruzione per trasferire il goto
controllo fuori dal membro della funzione corrente o in qualsiasi ambito annidato.
Specifiche del linguaggio C#
Per altre informazioni, vedere le sezioni seguenti delle specifiche del linguaggio C#: