Partager via


Instructions jump - break, , returncontinueetgoto

Les instructions de saut transfèrent inconditionnellement le contrôle. L’instructionbreak met fin à l’instruction ou switch à l’instructiond’itération la plus proche englobante. L’instructioncontinue démarre une nouvelle itération de l’instruction d’itération la plus proche englobante. L’instructionreturn met fin à l’exécution de la fonction dans laquelle elle apparaît et retourne le contrôle à l’appelant. L’instruction transfère le goto contrôle à une instruction marquée par une étiquette.

Pour plus d’informations sur l’instruction throw qui lève une exception et transfère sans condition le contrôle, consultez la section Instructions throw de l’article sur la gestion des exceptions.

L’instruction break.

L’instruction break met fin à l’instruction d’itération englobante la plus proche (autrement dit, , forforeach, whileou boucle) ou doswitch instruction. L’instruction break transfère le contrôle à l’instruction qui suit l’instruction terminée, le cas échéant.

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.

Dans les boucles imbriquées, l’instruction break met fin uniquement à la boucle la plus interne qui la contient, comme l’illustre l’exemple suivant :

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

Lorsque vous utilisez l’instruction switch à l’intérieur d’une boucle, une break instruction à la fin d’une section switch transfère le contrôle uniquement hors de l’instruction switch . La boucle qui contient l’instruction switch n’est pas affectée, comme l’illustre l’exemple suivant :

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.

L’instruction continue.

L’instruction continue démarre une nouvelle itération de l’instruction d’itération englobante la plus proche (autrement dit, c’est-à-dire, for, foreachwhileou do boucle), comme l’illustre l’exemple suivant :

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

L’instruction return.

L’instruction return met fin à l’exécution de la fonction dans laquelle elle apparaît et retourne le contrôle et le résultat de la fonction, le cas échéant, à l’appelant.

Si un membre de fonction ne calcule pas de valeur, vous utilisez l’instruction return sans expression, comme l’illustre l’exemple suivant :

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

Comme l’illustre l’exemple précédent, vous utilisez généralement l’instruction return sans expression pour arrêter un membre de fonction tôt. Si un membre de fonction ne contient pas l’instruction return , il se termine après l’exécution de sa dernière instruction.

Si un membre de fonction calcule une valeur, vous utilisez l’instruction return avec une expression, comme l’illustre l’exemple suivant :

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;
}

Lorsque l’instruction return a une expression, cette expression doit être implicitement convertible en type de retour d’un membre de fonction, sauf s’il est asynchrone. L’expression retournée à partir d’une async fonction doit être implicitement convertible en argument de type ou Task<TResult>ValueTask<TResult>, selon le type de retour de la fonction. Si le type de retour d’une async fonction est Task ou ValueTask, vous utilisez l’instruction return sans expression.

Retours ref

Par défaut, l’instruction return retourne la valeur d’une expression. Vous pouvez renvoyer une référence à une variable. Les valeurs de retour de référence (ou les retours ref) sont des valeurs qu’une méthode retourne par référence à l’appelant. Autrement dit, l’appelant peut modifier la valeur retournée par une méthode, et cette modification est reflétée dans l’état de l’objet dans la méthode appelée. Pour ce faire, utilisez l’instruction return avec le ref mot clé, comme l’illustre l’exemple suivant :

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.");
}

Une valeur de retour de référence permet à une méthode de retourner une référence à une variable, plutôt qu’une valeur, à un appelant. L’appelant peut ensuite choisir de traiter la variable retournée comme si elle était retournée par valeur ou par référence. L’appelant peut créer une variable qui est elle-même une référence à la valeur retournée, appelée ref local. Une valeur de retour de référence signifie qu’une méthode retourne une référence (ou un alias) à une variable. L’étendue de cette variable doit inclure la méthode. La durée de vie de cette variable doit s’étendre au-delà du retour de la méthode. Les modifications apportées à la valeur de retour de la méthode par l’appelant sont apportées à la variable retournée par la méthode.

La déclaration qu’une méthode retourne une valeur de retour de référence indique que la méthode retourne un alias à une variable. L’intention de conception est souvent que l’appel du code accède à cette variable via l’alias, y compris pour le modifier. Les méthodes retournées par référence ne peuvent pas avoir le type voidde retour .

Pour que l’appelant modifie l’état de l’objet, la valeur de retour de référence doit être stockée dans une variable définie explicitement comme variable de référence.

La ref valeur de retour est un alias vers une autre variable dans l’étendue de la méthode appelée. Vous pouvez interpréter n’importe quelle utilisation du retour ref comme à l’aide de la variable qu’il alias :

  • Lorsque vous attribuez sa valeur, vous affectez une valeur à la variable qu’il alias.
  • Lorsque vous lisez sa valeur, vous lisez la valeur de la variable qu’il alias.
  • Si vous le retournez par référence, vous retournez un alias à cette même variable.
  • Si vous le transmettez à une autre méthode par référence, vous transmettez une référence à la variable qu’il alias.
  • Lorsque vous créez un alias local ref , vous créez un nouvel alias dans la même variable.

Un retour ref doit être ref-safe-context à la méthode appelante. Cela signifie :

  • La valeur de retour doit avoir une durée de vie qui s’étend au-delà de l’exécution de la méthode. En d’autres termes, il ne peut pas s’agir d’une variable locale dans la méthode qui la retourne. Il peut s’agir d’une instance ou d’un champ statique d’une classe, ou d’un argument passé à la méthode. La tentative de retour d’une variable locale génère l’erreur du compilateur CS8168, « Impossible de renvoyer « obj » local par référence, car il ne s’agit pas d’un local ref. »
  • La valeur de retour ne peut pas être le littéral null. Une méthode avec un retour ref peut retourner un alias à une variable dont la valeur est actuellement la null valeur (ininstantiated) ou un type de valeur Nullable pour un type valeur.
  • La valeur de retour ne peut pas être une constante, un membre d’énumération, la valeur de retour par valeur d’une propriété ou une méthode d’un class ou struct.

En outre, les valeurs de retour de référence ne sont pas autorisées sur les méthodes asynchrones. Une méthode asynchrone peut retourner avant qu’elle n’ait terminé l’exécution, tandis que sa valeur de retour est toujours inconnue.

Une méthode qui retourne une valeur de retour de référence doit :

  • Incluez le mot clé ref devant le type de retour.
  • Chaque instruction return dans le corps de la méthode inclut le mot clé ref devant le nom de l’instance retournée.

L’exemple suivant montre une méthode qui répond à ces conditions et retourne une référence à un Person objet nommé p:

public ref Person GetContactInformation(string fname, string lname)
{
    // ...method implementation...
    return ref p;
}

Voici un exemple de retour ref plus complet, montrant à la fois la signature de méthode et le corps de la méthode.

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");
}

La méthode appelée peut également déclarer la valeur de retour pour ref readonly renvoyer la valeur par référence et appliquer que le code appelant ne peut pas modifier la valeur retournée. La méthode appelante peut éviter de copier la valeur retournée en stockant la valeur dans une variable de référence locale ref readonly .

L’exemple suivant définit une Book classe qui a deux String champs et AuthorTitle . Il définit également une BookCollection classe qui inclut un tableau privé d’objets Book . Les objets de livre individuels sont retournés par référence en appelant sa GetBookByTitle méthode.


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

Lorsque l’appelant stocke la valeur retournée par la GetBookByTitle méthode en tant que local ref, les modifications apportées par l’appelant à la valeur de retour sont reflétées dans l’objet BookCollection , comme l’illustre l’exemple suivant.

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

L’instruction goto.

L’instruction transfère le goto contrôle à une instruction marquée par une étiquette, comme l’illustre l’exemple suivant :

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.

Comme l’illustre l’exemple précédent, vous pouvez utiliser l’instruction goto pour sortir d’une boucle imbriquée.

Conseil / Astuce

Lorsque vous travaillez avec des boucles imbriquées, envisagez de refactoriser des boucles distinctes en méthodes distinctes. Cela peut entraîner un code plus simple et plus lisible sans l’instruction goto .

Vous pouvez également utiliser l’instruction dans l’instructionswitch pour transférer le goto contrôle vers une section switch avec une étiquette de casse constante, comme l’illustre l’exemple suivant :

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;
    }
}

Dans l’instruction switch , vous pouvez également utiliser l’instruction goto default; pour transférer le contrôle vers la section switch avec l’étiquette default .

Si une étiquette portant le nom donné n’existe pas dans le membre de la fonction actuelle ou si l’instruction goto n’est pas dans l’étendue de l’étiquette, une erreur au moment de la compilation se produit. Autrement dit, vous ne pouvez pas utiliser l’instruction pour transférer le goto contrôle hors du membre de fonction actuel ou dans n’importe quelle étendue imbriquée.

Spécification du langage C#

Pour plus d’informations, consultez les sections suivantes de la spécification du langage C# :

Voir aussi