Ugrási utasítások – break
, continue
, return
és goto
A jump utasítások feltétel nélkül átviszik az irányítást. Az break
utasítás leállítja a legközelebbi beágyazási iterációs utasítást vagy switch
utasítást. Az continue
utasítás a legközelebbi beágyazási iterációs utasítás új iterációját indítja el. Az return
utasítás leállítja annak a függvénynek a végrehajtását, amelyben megjelenik, és visszaadja az irányítást a hívónak. Az goto
utasítás egy címkével jelölt utasításra továbbítja a vezérlőt.
A kivételt okozó és feltétel nélküli átvitelt okozó utasítással kapcsolatos throw
információkért tekintse meg throw
a Kivételkezelési utasítások cikk Utasítás szakaszát.
Az break
utasítás
Az break
utasítás leállítja a legközelebbi beágyazási iterációs utasítást (azaz for
, , foreach
, while
vagy do
ciklust) vagy switch
utasítást. Az break
utasítás átviszi az irányítást a leállított utasítást követő utasításra, ha van ilyen.
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.
Beágyazott hurkokban az break
utasítás csak az azt tartalmazó legbelső hurkot szünteti meg, ahogy az alábbi példa is mutatja:
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
Ha egy cikluson belül használja az switch
utasítást, break
a kapcsolószakasz végén lévő utasítás csak az utasításon kívülre továbbítja a vezérlést switch
. Az utasítást switch
tartalmazó hurok nem változik, ahogy az alábbi példa is mutatja:
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.
Az continue
utasítás
Az continue
utasítás a legközelebbi beágyazási iterációs utasítás (azaz , , foreach
, while
vagy do
hurok) új iterációját indítja el, for
ahogyan az alábbi példa mutatja:
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
Az return
utasítás
Az return
utasítás leállítja annak a függvénynek a végrehajtását, amelyben megjelenik, és visszaadja a vezérlőt és a függvény eredményét, ha van ilyen, a hívónak.
Ha egy függvénytag nem számít ki értéket, a return
kifejezés nélküli utasítást használja, ahogy az alábbi példa is mutatja:
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
Ahogy az előző példa is mutatja, általában a return
kifejezés nélküli utasítást használja a függvénytagok korai leállításához. Ha egy függvénytag nem tartalmazza az return
utasítást, az utolsó utasítás végrehajtása után leáll.
Ha egy függvénytag kiszámít egy értéket, az return
utasítást egy kifejezéssel kell használnia, ahogy az alábbi példa mutatja:
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;
}
Ha az return
utasítás kifejezéssel rendelkezik, a kifejezésnek implicit módon konvertálhatónak kell lennie egy függvénytag visszatérési típusára, hacsak nem aszinkron. A függvényből async
visszaadott kifejezésnek implicit módon konvertálhatónak kell lennie a függvény típusargumentumára Task<TResult> , vagy ValueTask<TResult>attól függően, hogy melyik a függvény visszatérési típusa. Ha egy async
függvény visszatérési típusa vagy TaskValueTaska függvény visszatérési típusa, akkor az utasítást return
kifejezés nélkül használja.
Ref visszaadja
Alapértelmezés szerint az return
utasítás egy kifejezés értékét adja vissza. Egy változóra mutató hivatkozást is visszaadhat. A hivatkozási visszatérési értékek (vagy ref visszatérések) olyan értékek, amelyeket egy metódus a hívóra hivatkozva ad vissza. Vagyis a hívó módosíthatja a metódus által visszaadott értéket, és ez a változás az objektum állapotában tükröződik a hívott metódusban. Ehhez használja az utasítást return
a ref
kulcsszóval, ahogy az alábbi példa mutatja:
int[] 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.");
}
A hivatkozási visszatérési érték lehetővé teszi, hogy egy metódus egy változóra mutató hivatkozást adjon vissza érték helyett vissza egy hívónak. A hívó ezután úgy kezelheti a visszaadott változót, mintha érték vagy hivatkozás alapján lett volna visszaadva. A hívó létrehozhat egy új változót, amely önmagában a visszaadott értékre mutató hivatkozás, úgynevezett ref local. A referencia-visszatérési érték azt jelenti, hogy egy metódus egy adott változóra mutató hivatkozást (vagy aliast) ad vissza. A változó hatókörének tartalmaznia kell a metódust. A változó élettartamának meg kell hosszabbodnia a metódus visszatérésén. A hívó módosítja a metódus visszatérési értékét a metódus által visszaadott változón.
Ha egy metódus hivatkozási visszatérési értéket ad vissza, az azt jelzi, hogy a metódus egy aliast ad vissza egy változónak. A tervezési szándék gyakran az, hogy a kód meghívása az aliason keresztül éri el a változót, beleértve a módosítást is. A hivatkozással visszaadott metódusok visszatérési típusa void
nem lehet.
Ahhoz, hogy a hívó módosíthassa az objektum állapotát, a referencia visszatérési értékét egy olyan változóban kell tárolni, amely kifejezetten referenciaváltozóként van definiálva.
A ref
visszatérési érték egy alias egy másik változóhoz az úgynevezett metódus hatókörében. A hiv visszatérési függvény bármilyen használatát az általa aliasként megadott változóként értelmezheti:
- Az érték hozzárendelésekor egy értéket rendel hozzá az általa aliasként használt változóhoz.
- Amikor elolvassa az értékét, az általa aliasként használt változó értékét olvassa.
- Ha hivatkozással adja vissza, egy aliast ad vissza ugyanahhoz a változóhoz.
- Ha hivatkozással egy másik metódusnak adja át, az aliasok változóra mutató hivatkozást ad át.
- Ha helyi aliast hoz létre, új aliast hoz létre ugyanahhoz a változóhoz.
A hiv-visszatérésnek a hívási metódusra vonatkozó ref-safe-context-nek kell lennie. Ez a következőt jelenti:
- A visszatérési értéknek olyan élettartamúnak kell lennie, amely túllépi a metódus végrehajtását. Más szóval nem lehet helyi változó a visszaadott metódusban. Lehet egy osztály példánya vagy statikus mezője, vagy lehet a metódusnak átadott argumentum. Ha megpróbál egy helyi változót visszaadni, az a CS8168-at generálja, a "Nem lehet a helyi "obj"-t hivatkozással visszaadni, mert az nem hiv helyi."
- A visszatérési érték nem lehet a literál
null
. A ref visszatérési értékkel rendelkező metódusok olyan változónak adhatnak vissza aliast, amelynek értéke jelenleg anull
(nem telepített) érték, vagy egy értéktípus null értékű értéktípusa . - A visszatérési érték nem lehet állandó, enumerálási tag, tulajdonságból származó bájt visszatérési érték, vagy egy
class
vagystruct
.
Emellett a referencia visszatérési értékei nem engedélyezettek az aszinkron metódusokban. Az aszinkron metódus a végrehajtás befejezése előtt visszatérhet, a visszatérési értéke azonban még ismeretlen.
A hivatkozási visszatérési értéket visszaadó metódusnak a következőnek kell lennie:
- Adja meg a ref kulcsszót a visszatérési típus elé.
- A metódus törzsében minden visszatérési utasítás tartalmazza a ref kulcsszót a visszaadott példány neve előtt.
Az alábbi példa egy olyan metódust mutat be, amely megfelel ezeknek a feltételeknek, és egy, a Person
következő nevű p
objektumra mutató hivatkozást ad vissza:
public ref Person GetContactInformation(string fname, string lname)
{
// ...method implementation...
return ref p;
}
Íme egy teljesebb ref visszatérési példa, amely a metódus aláírását és a metódus törzsét is megjeleníti.
public static ref int Find(int[,] matrix, Func<int, bool> predicate)
{
for (int i = 0; i < matrix.GetLength(0); i++)
for (int j = 0; j < matrix.GetLength(1); j++)
if (predicate(matrix[i, j]))
return ref matrix[i, j];
throw new InvalidOperationException("Not found");
}
A hívott metódus a visszatérési értéket ref readonly
úgy is deklarálhatja, hogy hivatkozással adja vissza az értéket, és kényszerítheti, hogy a hívó kód ne tudja módosítani a visszaadott értéket. A hívási módszer elkerülheti a visszaadott érték másolását úgy, hogy az értéket egy helyi ref readonly
referenciaváltozóban tárolja.
Az alábbi példa egy olyan osztályt Book
határoz meg, Title
amely két String mezővel és Author
. Emellett definiál egy osztályt BookCollection
is, amely egy privát objektumtömböt Book
tartalmaz. Az egyes könyvobjektumokat a rendszer hivatkozással adja vissza a metódus meghívásával GetBookByTitle
.
public class Book
{
public string Author;
public string Title;
}
public class BookCollection
{
private Book[] books = { new Book { Title = "Call of the Wild, The", Author = "Jack London" },
new Book { Title = "Tale of Two Cities, A", Author = "Charles Dickens" }
};
private Book nobook = null;
public ref Book GetBookByTitle(string title)
{
for (int ctr = 0; ctr < books.Length; ctr++)
{
if (title == books[ctr].Title)
return ref books[ctr];
}
return ref nobook;
}
public void ListBooks()
{
foreach (var book in books)
{
Console.WriteLine($"{book.Title}, by {book.Author}");
}
Console.WriteLine();
}
}
Amikor a hívó a metódus által GetBookByTitle
visszaadott értéket ref localként tárolja, a hívó által a visszatérési értéken végrehajtott módosítások megjelennek az BookCollection
objektumban, ahogy az alábbi példa is mutatja.
var bc = new BookCollection();
bc.ListBooks();
ref var book = ref bc.GetBookByTitle("Call of the Wild, The");
if (book != null)
book = new Book { Title = "Republic, The", Author = "Plato" };
bc.ListBooks();
// The example displays the following output:
// Call of the Wild, The, by Jack London
// Tale of Two Cities, A, by Charles Dickens
//
// Republic, The, by Plato
// Tale of Two Cities, A, by Charles Dickens
Az goto
utasítás
Az goto
utasítás egy címkével jelölt utasításra továbbítja a vezérlőt, ahogy az az alábbi példában látható:
var matrices = new Dictionary<string, int[][]>
{
["A"] =
[
[1, 2, 3, 4],
[4, 3, 2, 1]
],
["B"] =
[
[5, 6, 7, 8],
[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.
Ahogy az előző példa is mutatja, az goto
utasítással kiléphet egy beágyazott hurokból.
Tipp.
Ha beágyazott hurkokkal dolgozik, fontolja meg a különálló hurkok újrabontását külön metódusokba. Ez egy egyszerűbb, olvashatóbb kódhoz vezethet az goto
utasítás nélkül.
Az utasításban szereplő switch
utasítással goto
a vezérlőelemet állandó kisbetűs címkével ellátott kapcsolószakaszba is áthelyezheti, ahogyan az alábbi példa mutatja:
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;
}
}
Az utasításon switch
belül az utasítással goto default;
át is helyezheti a vezérlőt a címkével ellátott default
kapcsolószakaszra.
Ha a megadott névvel rendelkező címke nem létezik az aktuális függvénytagban, vagy ha az goto
utasítás nem tartozik a címke hatókörébe, fordítási időhiba lép fel. Ez azt is jelentheti, hogy az utasítással nem helyezheti át az goto
irányítást az aktuális függvénytagból vagy egy beágyazott hatókörbe.
C# nyelvspecifikáció
További információt a C# nyelvspecifikációjának alábbi szakaszaiban talál: