Megosztás a következőn keresztül:


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 throwa 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, whilevagy 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, whilevagy do hurok) új iterációját indítja el, forahogyan 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 voidnem 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 a null (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 vagy struct.

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:

Az alábbi példa egy olyan metódust mutat be, amely megfelel ezeknek a feltételeknek, és egy, a Person következő nevű pobjektumra 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:

Lásd még