Méthodes en C#

Une méthode est un bloc de code qui contient une série d'instructions. Un programme provoque l'exécution des instructions en appelant la méthode et en spécifiant les éventuels arguments de méthode requis. En C#, chaque instruction exécutée est effectuée dans le contexte d'une méthode. La méthode Main est le point d’entrée de chaque application C# et elle est appelée par le Common Language Runtime (CLR) au démarrage du programme.

Notes

Cette rubrique décrit les méthodes nommées. Pour plus d’informations sur les fonctions anonymes, consultez Expressions lambda.

Signatures de méthode

Les méthodes sont déclarées dans class, record ou struct en spécifiant :

  • Un niveau d’accès facultatif, comme public ou private. Par défaut, il s’agit de private.
  • Des modificateurs facultatifs, comme abstract ou sealed.
  • La valeur de retour, ou void si la méthode n’en a pas.
  • Nom de la méthode.
  • Des paramètres de méthodes. Les paramètres de méthode sont placés entre parenthèses et séparés par des virgules. Des parenthèses vides indiquent que la méthode ne requiert aucun paramètre.

Ces parties forment ensemble la signature de la méthode.

Important

Un type de retour d'une méthode ne fait pas partie de la signature de la méthode à des fins de surcharge de méthode. Toutefois, il fait partie de la signature de la méthode lors de la détermination de la compatibilité entre un délégué et la méthode vers laquelle il pointe.

L’exemple suivant définit une classe nommée Motorcycle qui contient cinq méthodes :

namespace MotorCycleExample
{
    abstract class Motorcycle
    {
        // Anyone can call this.
        public void StartEngine() {/* Method statements here */ }

        // Only derived classes can call this.
        protected void AddGas(int gallons) { /* Method statements here */ }

        // Derived classes can override the base class implementation.
        public virtual int Drive(int miles, int speed) { /* Method statements here */ return 1; }

        // Derived classes can override the base class implementation.
        public virtual int Drive(TimeSpan time, int speed) { /* Method statements here */ return 0; }

        // Derived classes must implement this.
        public abstract double GetTopSpeed();
    }

La classe Motorcycle inclut une méthode surchargée, Drive. Deux méthodes ont le même nom, mais doivent être différenciées par leurs types de paramètre.

Appel de méthode

Les méthodes peuvent être d’instance ou statiques. L’appel d’une méthode d’instance nécessite l’instanciation d’un objet et l’appel de la méthode sur cet objet ; une méthode d’instance agit sur cette instance et sur ses données. Vous appelez une méthode statique en référençant le nom du type auquel la méthode appartient ; les méthodes statiques n’agissent pas sur les données d’une instance. Une tentative d’appeler une méthode statique via une instance d’objet génère une erreur du compilateur.

Appeler une méthode est comme accéder à un champ. Après le nom d’objet (si vous appelez une méthode d’instance) ou le nom de type (si vous appelez une méthode static), ajoutez un point, le nom de la méthode et des parenthèses. Les arguments sont répertoriés entre les parenthèses et séparés par des virgules.

La définition de la méthode spécifie les noms et types des paramètres requis. Quand un appelant appelle la méthode, il fournit des valeurs réelles, appelées « arguments », pour chaque paramètre. Les arguments doivent être compatibles avec le type de paramètre, mais le nom de l’argument, si un nom est utilisé dans le code appelant, ne doit pas nécessairement être le même que celui du paramètre défini dans la méthode. Dans l’exemple suivant, la méthode Square comprend un seul paramètre de type int nommé i. Le premier appel de la méthode passe à la méthode Square une variable de type int nommée num, le deuxième appel passe une constante numérique et le troisième appel passe une expression.

public static class SquareExample
{
    public static void Main()
    {
        // Call with an int variable.
        int num = 4;
        int productA = Square(num);

        // Call with an integer literal.
        int productB = Square(12);

        // Call with an expression that evaluates to int.
        int productC = Square(productA * 3);
    }

    static int Square(int i)
    {
        // Store input argument in a local variable.
        int input = i;
        return input * input;
    }
}

La forme la plus courante des appels de méthode utilise des arguments de position ; elle fournit les arguments dans le même ordre que celui des paramètres de la méthode. Les méthodes de la classe Motorcycle peuvent donc être appelées comme dans l’exemple suivant. Par exemple, l’appel à la méthode Drive comprend deux arguments qui correspondent aux deux paramètres de la syntaxe de la méthode. Le premier devient la valeur du paramètre miles et le deuxième devient la valeur du paramètre speed.

class TestMotorcycle : Motorcycle
{
    public override double GetTopSpeed() => 108.4;

    static void Main()
    {
        var moto = new TestMotorcycle();

        moto.StartEngine();
        moto.AddGas(15);
        _ = moto.Drive(5, 20);
        double speed = moto.GetTopSpeed();
        Console.WriteLine("My top speed is {0}", speed);
    }
}

Vous pouvez également utiliser des arguments nommés au lieu d’arguments positionnels lors de l’appel d’une méthode. Lors de l’utilisation d’arguments nommés, vous spécifiez le nom du paramètre suivi de deux-points (« : ») et de l’argument. Les arguments de la méthode peuvent apparaître dans n’importe quel ordre, dès lors que tous les arguments nécessaires sont présents. L’exemple suivant utilise des arguments nommés pour appeler la méthode TestMotorcycle.Drive. Dans cet exemple, les arguments nommés sont passés dans l’ordre inverse de celui de la liste des paramètres de la méthode.

namespace NamedMotorCycle;

class TestMotorcycle : Motorcycle
{
    public override int Drive(int miles, int speed) =>
        (int)Math.Round((double)miles / speed, 0);

    public override double GetTopSpeed() => 108.4;

    static void Main()
    {
        var moto = new TestMotorcycle();
        moto.StartEngine();
        moto.AddGas(15);
        int travelTime = moto.Drive(miles: 170, speed: 60);
        Console.WriteLine("Travel time: approx. {0} hours", travelTime);
    }
}
// The example displays the following output:
//      Travel time: approx. 3 hours

Vous pouvez appeler une méthode en utilisant à la fois des arguments positionnels et des arguments nommés. Toutefois, les arguments positionnels ne peuvent suivre les arguments nommés que lorsque les arguments nommés se trouvent dans des positions correctes. L’exemple suivant appelle la méthode TestMotorcycle.Drive de l’exemple précédent en utilisant un argument positionnel et un argument nommé.

int travelTime = moto.Drive(170, speed: 55);

Méthodes hérités et remplacées

En plus des membres qui sont définis explicitement dans un type, un type hérite des membres définis dans ses classes de base. Comme tous les types du système de types managés héritent directement ou indirectement de la classe Object, tous les types héritent ses membres, comme Equals(Object), GetType() et ToString(). L’exemple suivant définit une classe Person, instancie deux objets Person et appelle la méthode Person.Equals pour déterminer si les deux objets sont égaux. La méthode Equals n’est cependant pas définie dans la classe Person ; elle est héritée de Object.

public class Person
{
    public string FirstName = default!;
}

public static class ClassTypeExample
{
    public static void Main()
    {
        Person p1 = new() { FirstName = "John" };
        Person p2 = new() { FirstName = "John" };
        Console.WriteLine("p1 = p2: {0}", p1.Equals(p2));
    }
}
// The example displays the following output:
//      p1 = p2: False

Vous pouvez remplacer des membres hérités par des types en utilisant le mot clé override et en fournissant une implémentation de la méthode remplacée. La signature de la méthode doit être identique à celle de la méthode remplacée. L’exemple suivant est semblable au précédent, sauf qu’il remplace la méthode Equals(Object). (Il remplace aussi la méthode GetHashCode(), car les deux méthodes sont destinées à fournir des résultats cohérents.)

namespace methods;

public class Person
{
    public string FirstName = default!;

    public override bool Equals(object? obj) =>
        obj is Person p2 &&
        FirstName.Equals(p2.FirstName);

    public override int GetHashCode() => FirstName.GetHashCode();
}

public static class Example
{
    public static void Main()
    {
        Person p1 = new() { FirstName = "John" };
        Person p2 = new() { FirstName = "John" };
        Console.WriteLine("p1 = p2: {0}", p1.Equals(p2));
    }
}
// The example displays the following output:
//      p1 = p2: True

Passage de paramètres

Les types en C# sont des types valeur ou des types référence. Pour obtenir la liste des types valeur intégrés, consultez Types. Par défaut, les types valeur et les types référence sont passés par valeur à une méthode.

Passage de paramètres par valeur

Quand un type valeur est passé par valeur à une méthode, c’est une copie de l’objet, et non pas l’objet lui-même, qui est passée à la méthode. Par conséquent, les modifications de l’objet dans la méthode appelée n’ont pas d’effet sur l’objet d’origine quand le contrôle retourne à l’appelant.

L’exemple suivant passe un type valeur à une méthode par valeur, et la méthode appelée tente de changer la valeur du type valeur. Il définit une variable de type int, qui est un type valeur, initialise sa valeur à 20 et la passe à une méthode nommée ModifyValue qui change la valeur de la variable en 30. Quand la méthode retourne, la valeur de la variable reste cependant inchangée.

public static class ByValueExample
{
    public static void Main()
    {
        var value = 20;
        Console.WriteLine("In Main, value = {0}", value);
        ModifyValue(value);
        Console.WriteLine("Back in Main, value = {0}", value);
    }

    static void ModifyValue(int i)
    {
        i = 30;
        Console.WriteLine("In ModifyValue, parameter value = {0}", i);
        return;
    }
}
// The example displays the following output:
//      In Main, value = 20
//      In ModifyValue, parameter value = 30
//      Back in Main, value = 20

Quand un objet d’un type référence est passé par valeur à une méthode, c’est une référence à l’objet qui est passée par valeur. Autrement dit, la méthode ne reçoit pas l’objet lui-même mais un argument qui indique l’emplacement de l’objet. Si vous modifiez un membre de l’objet en utilisant cette référence, la modification est répercutée dans l’objet quand le contrôle retourne à la méthode appelante. Cependant, remplacer l’objet passé à la méthode n’a pas d’effet sur l’objet d’origine quand le contrôle retourne à l’appelant.

L’exemple suivant définit une classe (qui est un type référence) nommée SampleRefType. Il instancie un objet SampleRefType, affecte la valeur 44 à son champ value et passe l’objet à la méthode ModifyObject. L’exemple fait essentiellement la même chose que l’exemple précédent : il passe un argument par valeur à une méthode. Cependant, comme il utilise un type référence, le résultat est différent. La modification apportée dans ModifyObject au champ obj.value change également en 33 le champ value de l’argument rt dans la méthode Main, comme le montre le résultat de l’exemple.

public class SampleRefType
{
    public int value;
}

public static class ByRefTypeExample
{
    public static void Main()
    {
        var rt = new SampleRefType { value = 44 };
        ModifyObject(rt);
        Console.WriteLine(rt.value);
    }

    static void ModifyObject(SampleRefType obj) => obj.value = 33;
}

Passage de paramètres par référence

On passe un paramètre par référence quand on souhaite changer la valeur d’un argument dans une méthode et refléter cette modification lorsque le contrôle revient à la méthode appelante. Pour passer un paramètre par référence, vous utilisez le mot clé ref ou out. Vous pouvez également passer une valeur par référence pour éviter la copie tout en empêchant les modifications à l’aide du mot clé in.

L’exemple suivant est identique au précédent, sauf que la valeur est passée par référence à la méthode ModifyValue. Quand la valeur du paramètre est modifiée dans la méthode ModifyValue, le changement de la valeur est reflété quand le contrôle retourne à l’appelant.

public static class ByRefExample
{
    public static void Main()
    {
        var value = 20;
        Console.WriteLine("In Main, value = {0}", value);
        ModifyValue(ref value);
        Console.WriteLine("Back in Main, value = {0}", value);
    }

    private static void ModifyValue(ref int i)
    {
        i = 30;
        Console.WriteLine("In ModifyValue, parameter value = {0}", i);
        return;
    }
}
// The example displays the following output:
//      In Main, value = 20
//      In ModifyValue, parameter value = 30
//      Back in Main, value = 30

Un modèle courant qui utilise des paramètres par référence implique la permutation des valeurs des variables. Vous passez deux variables à une méthode par référence, et la méthode permute leur contenu. L’exemple suivant permute des valeurs d’entier.


public static class RefSwapExample
{
    static void Main()
    {
        int i = 2, j = 3;
        Console.WriteLine("i = {0}  j = {1}", i, j);

        Swap(ref i, ref j);

        Console.WriteLine("i = {0}  j = {1}", i, j);
    }

    static void Swap(ref int x, ref int y) =>
        (y, x) = (x, y);
}
// The example displays the following output:
//      i = 2  j = 3
//      i = 3  j = 2

Passer un paramètre de type référence vous permet de changer la valeur de la référence elle-même, au lieu de la valeur de ses éléments ou champs individuels.

Tableaux de paramètres

Parfois, l’obligation de spécifier le nombre exact d’arguments de votre méthode est restrictive. En utilisant le mot clé params pour indiquer qu’un paramètre est un tableau de paramètres, vous permettez que votre méthode soit appelée avec un nombre variable d’arguments. Le paramètre marqué avec le mot clé params doit être un type tableau. Ce doit être le dernier paramètre de la liste de paramètres de la méthode.

Un appelant peut alors appeler la méthode de quatre façons :

  • En passant un tableau du type approprié, qui contient le nombre d’éléments souhaité.
  • En passant une liste d’arguments individuels séparés par des virgules et du type approprié à la méthode.
  • En passant null.
  • En ne fournissant pas d’argument au tableau de paramètres.

L’exemple suivant définit une méthode nommée GetVowels qui retourne toutes les voyelles à partir d’un tableau de paramètres. La méthode Main montre les quatre façons d’appeler la méthode. Les appelants n’ont pas nécessairement à fournir tous les arguments pour les paramètres qui incluent le modificateur params. Dans ce cas, le paramètre est un tableau vide.

static class ParamsExample
{
    static void Main()
    {
        string fromArray = GetVowels(["apple", "banana", "pear"]);
        Console.WriteLine($"Vowels from array: '{fromArray}'");

        string fromMultipleArguments = GetVowels("apple", "banana", "pear");
        Console.WriteLine($"Vowels from multiple arguments: '{fromMultipleArguments}'");

        string fromNull = GetVowels(null);
        Console.WriteLine($"Vowels from null: '{fromNull}'");

        string fromNoValue = GetVowels();
        Console.WriteLine($"Vowels from no value: '{fromNoValue}'");
    }

    static string GetVowels(params string[]? input)
    {
        if (input == null || input.Length == 0)
        {
            return string.Empty;
        }

        char[] vowels = ['A', 'E', 'I', 'O', 'U'];
        return string.Concat(
            input.SelectMany(
                word => word.Where(letter => vowels.Contains(char.ToUpper(letter)))));
    }
}

// The example displays the following output:
//     Vowels from array: 'aeaaaea'
//     Vowels from multiple arguments: 'aeaaaea'
//     Vowels from null: ''
//     Vowels from no value: ''

Paramètres et arguments facultatifs

Une définition de méthode peut spécifier que ses paramètres sont obligatoires ou facultatifs. Par défaut, les paramètres sont obligatoires. Vous spécifiez des paramètres facultatifs en incluant la valeur par défaut du paramètre dans la définition de la méthode. Quand la méthode est appelée, si aucun argument n’est fourni pour un paramètre facultatif, c’est la valeur par défaut qui est utilisée à la place.

La valeur par défaut du paramètre doit être affectée par un des types d’expressions suivants :

  • Une constante, comme une chaîne littérale ou un nombre.

  • Une expression de la forme default(SomeType), où SomeType peut être un type valeur ou un type référence. S’il s’agit d’un type référence, il s’agit de la même chose que de spécifier null. Vous pouvez utiliser le littéral default, car le compilateur peut déduire le type à partir de la déclaration du paramètre.

  • Une expression de la forme new ValType(), où ValType est un type valeur. Ceci appelle le constructeur sans paramètre implicite du type valeur, qui n’est pas un membre réel du type.

    Notes

    Dans C# 10 et versions ultérieures, lorsqu’une expression du formulaire new ValType() appelle le constructeur sans paramètre explicitement défini d’un type valeur, le compilateur génère une erreur, car la valeur de paramètre par défaut doit être une constante de compilation. Utilisez l’expression default(ValType) ou le littéral default pour fournir la valeur de paramètre par défaut. Pour plus d’informations sur les constructeurs sans paramètre, consultez la section Initialisation de struct et valeurs par défaut de l’article Types de structure.

Si une méthode comprend à la fois des paramètres obligatoires et des paramètres facultatifs, les paramètres facultatifs sont définis à la fin de la liste des paramètres, après tous les paramètres obligatoires.

L’exemple suivant définit une méthode, ExampleMethod, qui a un paramètre obligatoire et deux paramètres facultatifs.

public class Options
{
    public void ExampleMethod(int required, int optionalInt = default,
                              string? description = default)
    {
        var msg = $"{description ?? "N/A"}: {required} + {optionalInt} = {required + optionalInt}";
        Console.WriteLine(msg);
    }
}

Si une méthode avec plusieurs arguments facultatifs est appelée en utilisant des arguments positionnels, l’appelant doit fournir un argument pour tous les paramètres facultatifs, du premier au dernier pour lequel un argument est fourni. Par exemple, dans le cas de la méthode ExampleMethod, si l’appelant fournit un argument pour le paramètre description, il doit également en fournir un pour le paramètre optionalInt. opt.ExampleMethod(2, 2, "Addition of 2 and 2"); est un appel de méthode valide. opt.ExampleMethod(2, , "Addition of 2 and 0"); génère une erreur du compilateur « Argument manquant ».

Si une méthode est appelée en utilisant des arguments nommés ou une combinaison d’arguments positionnels et nommés, l’appelant peut omettre les arguments qui suivent le dernier argument positionnel dans l’appel de la méthode.

L’exemple suivant appelle la méthode ExampleMethod trois fois. Les deux premiers appels de la méthode utilisent des arguments positionnels. Le premier omet les deux arguments facultatifs, tandis que le deuxième omet le dernier argument. Le troisième appel de la méthode fournit un argument positionnel pour le paramètre obligatoire, mais utilise un argument nommé pour fournir une valeur au paramètre description tout en omettant l’argument optionalInt.

public static class OptionsExample
{
    public static void Main()
    {
        var opt = new Options();
        opt.ExampleMethod(10);
        opt.ExampleMethod(10, 2);
        opt.ExampleMethod(12, description: "Addition with zero:");
    }
}
// The example displays the following output:
//      N/A: 10 + 0 = 10
//      N/A: 10 + 2 = 12
//      Addition with zero:: 12 + 0 = 12

L’utilisation de paramètres facultatifs affecte la résolution de la surcharge, qui est la façon dont le compilateur C# détermine quelle surcharge particulière doit être appelée par un appel de méthode, comme suit :

  • Une méthode, un indexeur ou un constructeur est un candidat pour l’exécution si chacun de ses paramètres est facultatif ou correspond, par nom ou par position, à un seul argument dans l’instruction appelante, et que cet argument peut être converti vers le type du paramètre.
  • Si plusieurs candidats sont trouvés, les règles de résolution de surcharge des conversions préférées sont appliquées aux arguments qui sont explicitement spécifiés. Les arguments omis pour les paramètres facultatifs sont ignorés.
  • Si deux candidats sont jugés de qualité équivalente, la préférence va à celui qui n’a pas de paramètres facultatifs pour lesquels des arguments ont été omis dans l’appel. Ceci est une conséquence d’une préférence générale dans la résolution de la surcharge pour les candidats qui ont le moins de paramètres.

Valeurs de retour

Les méthodes peuvent retourner une valeur à l'appelant. Si le type de retour (le type qui figure avant le nom de la méthode) n’est pas void, la méthode peut retourner la valeur en utilisant le mot clé return. Une instruction avec le mot clé return suivi d’une variable, d’une constante ou d’une expression qui correspond au type de retour retourne cette valeur à l’appelant de la méthode. Les méthodes dotées d'un type de retour non void doivent utiliser le mot clé return pour retourner une valeur. Le mot clé return arrête également l'exécution de la méthode.

Si le type de retour est void, une instruction return sans valeur est quand même utile pour arrêter l'exécution de la méthode. Sans le mot clé return , la méthode arrête de s'exécuter quand elle atteint la fin du bloc de code.

Par exemple, ces deux méthodes utilisent le mot clé return pour retourner des entiers :

class SimpleMath
{
    public int AddTwoNumbers(int number1, int number2) =>
        number1 + number2;

    public int SquareANumber(int number) =>
        number * number;
}

Pour utiliser une valeur retournée à partir d'une méthode, la méthode d'appel peut utiliser l'appel de méthode proprement dit partout où une valeur du même type peut suffire. Vous pouvez également affecter la valeur de retour à une variable. Par exemple, les deux exemples de code suivants remplissent le même objectif :

int result = obj.AddTwoNumbers(1, 2);
result = obj.SquareANumber(result);
// The result is 9.
Console.WriteLine(result);
result = obj.SquareANumber(obj.AddTwoNumbers(1, 2));
// The result is 9.
Console.WriteLine(result);

L'utilisation d'une variable locale, dans cet exemple, result, pour stocker une valeur est facultative. Elle peut favoriser la lisibilité du code ou s'avérer nécessaire si vous avez besoin de stocker la valeur d'origine de l'argument pour la portée entière de la méthode.

Vous voulez parfois que votre méthode retourne plusieurs valeurs. Vous pouvez faire cela facilement en utilisant des types tuple et des littéraux de tuple. Le type tuple définit les types de données des éléments du tuple. Les littéraux de tuple fournissent les valeurs réelles du tuple retourné. Dans l’exemple suivant, (string, string, string, int) définit le type tuple retourné par la méthode GetPersonalInfo. L’expression (per.FirstName, per.MiddleName, per.LastName, per.Age) est le littéral de tuple ; la méthode retourne le prénom, le deuxième prénom et le nom, ainsi que l’âge pour un objet PersonInfo.

public (string, string, string, int) GetPersonalInfo(string id)
{
    PersonInfo per = PersonInfo.RetrieveInfoById(id);
    return (per.FirstName, per.MiddleName, per.LastName, per.Age);
}

L’appelant peut alors consommer le tuple retourné avec du code comme celui-ci :

var person = GetPersonalInfo("111111111");
Console.WriteLine($"{person.Item1} {person.Item3}: age = {person.Item4}");

Vous pouvez aussi affecter des noms aux éléments du tuple dans la définition du type tuple. L’exemple suivant montre une autre version de la méthode GetPersonalInfo qui utilise des éléments nommés :

public (string FName, string MName, string LName, int Age) GetPersonalInfo(string id)
{
    PersonInfo per = PersonInfo.RetrieveInfoById(id);
    return (per.FirstName, per.MiddleName, per.LastName, per.Age);
}

L’appel précédent de la méthode GetPersonalInfo peut alors être modifié comme suit :

var person = GetPersonalInfo("111111111");
Console.WriteLine($"{person.FName} {person.LName}: age = {person.Age}");

Si un tableau est passé comme argument à une méthode et que celle-ci modifie la valeur d’éléments individuels, il n’est pas nécessaire que la méthode retourne le tableau, même si vous pouvez choisir de le faire pour la qualité du style ou pour obtenir un flux fonctionnel de valeurs. La raison en est que C# passe tous les types référence par valeur et que la valeur d’une référence de tableau est le pointeur vers ce tableau. Dans l’exemple suivant, les modifications apportées au contenu du tableau values qui sont effectuées dans la méthode DoubleValues sont observables par tout code ayant une référence au tableau.


public static class ArrayValueExample
{
    static void Main()
    {
        int[] values = [2, 4, 6, 8];
        DoubleValues(values);
        foreach (var value in values)
        {
            Console.Write("{0}  ", value);
        }
    }

    public static void DoubleValues(int[] arr)
    {
        for (var ctr = 0; ctr <= arr.GetUpperBound(0); ctr++)
        {
            arr[ctr] *= 2;
        }
    }
}
// The example displays the following output:
//       4  8  12  16

Méthodes d’extension

En règle générale, il existe deux façons d’ajouter une méthode à un type existant :

  • Modifier le code source pour ce type. Vous ne pouvez évidemment pas le faire si vous ne disposez pas du code source du type. D’autre part, ceci devient une modification d’importance si vous ajoutez aussi des champs de données privés pour prendre en charge la méthode.
  • Définir la nouvelle méthode dans une classe dérivée. Vous ne pouvez pas ajouter une méthode de cette façon en utilisant l’héritage pour d’autres types, comme des structures et des énumérations. Vous ne pouvez pas non plus l’utiliser pour « ajouter » une méthode à une classe scellée.

Les méthodes d’extension vous permettent d’« ajouter » une méthode à un type existant sans modifier le type lui-même, ou en implémentant la nouvelle méthode dans un type hérité. La méthode d’extension ne doit pas non plus nécessairement se trouver dans le même assembly que le type qu’elle étend. Vous appelez une méthode d’extension comme si elle était un membre défini d’un type.

Pour plus d’informations, consultez Méthodes d’extension.

Méthodes async

La fonctionnalité async vous permet d'appeler des méthodes asynchrones sans utiliser de rappels explicites ni fractionner manuellement votre code entre plusieurs méthodes ou expressions lambda.

Si vous marquez une méthode avec le modificateur async, vous pouvez utiliser l’opérateur await dans la méthode. Quand le contrôle atteint une expression await dans la méthode async, il retourne à l’appelant si la tâche attendue n’est pas terminée, et la progression dans la méthode avec le mot clé await est interrompue jusqu’à ce que la tâche attendue se termine. Quand la tâche est terminée, l'exécution peut reprendre dans la méthode.

Notes

Une méthode asynchrone retourne à l'appelant quand elle rencontre le premier objet attendu qui n'est pas encore terminé ou quand elle atteint la fin de la méthode asynchrone, selon la première éventualité.

Une méthode asynchrone a généralement un type de retour Task<TResult>, Task, IAsyncEnumerable<T> ou void . Le type de retour void est essentiellement utilisé pour définir les gestionnaires d’événements, où un type de retour void est obligatoire. Une méthode async qui retourne void ne peut pas être attendue, et l’appelant d’une méthode retournant void ne peut intercepter aucune exception levée par la méthode. Une méthode asynchrone peut avoir n’importe quel type de retour de type tâche.

Dans l’exemple suivant, DelayAsync est une méthode async contenant une instruction return qui retourne un entier. Comme il s’agit d’une méthode async, la déclaration de sa méthode doit avoir un type de retour Task<int>. Comme le type de retour est Task<int>, l’évaluation de l’expression await dans DoSomethingAsync produit un entier, comme l’instruction int result = await delayTask suivante le montre.

class Program
{
    static Task Main() => DoSomethingAsync();

    static async Task DoSomethingAsync()
    {
        Task<int> delayTask = DelayAsync();
        int result = await delayTask;

        // The previous two statements may be combined into
        // the following statement.
        //int result = await DelayAsync();

        Console.WriteLine($"Result: {result}");
    }

    static async Task<int> DelayAsync()
    {
        await Task.Delay(100);
        return 5;
    }
}
// Example output:
//   Result: 5

Une méthode async ne peut pas déclarer de paramètres in, ref ou out, mais elle peut appeler des méthodes qui ont ces paramètres.

Pour plus d’informations sur les méthodes asynchrones, consultez Programmation asynchrone avec asynchrone et await et Types de retour asynchrones.

Membres expression-bodied

Il est courant d'avoir des définitions de méthode qui retournent tout simplement le résultat d'une expression immédiatement, ou qui ont une seule instruction en tant que corps de la méthode. Il existe un raccourci de syntaxe pour définir de telles méthodes en utilisant=> :

public Point Move(int dx, int dy) => new Point(x + dx, y + dy);
public void Print() => Console.WriteLine(First + " " + Last);
// Works with operators, properties, and indexers too.
public static Complex operator +(Complex a, Complex b) => a.Add(b);
public string Name => First + " " + Last;
public Customer this[long id] => store.LookupCustomer(id);

Si la méthode retourne void ou est une méthode async, alors le corps de la méthode doit être une expression d’instruction (comme avec les expressions lambda). En ce qui concerne les propriétés et indexeurs, ils doivent être en lecture seule et vous n'utilisez pas le mot clé d'accesseur get.

Iterators

Un itérateur exécute une itération personnalisée sur une collection, comme une liste ou un tableau. Un itérateur utilise l'instruction yield return pour retourner chaque élément un par un. Quand une instruction yield return est atteinte, l’emplacement actif est mémorisé pour que l’appelant puisse demander l’élément suivant dans la séquence.

Le type de retour d'un itérateur peut être IEnumerable, IEnumerable<T>, IAsyncEnumerable<T>, IEnumerator ou IEnumerator<T>.

Pour plus d'informations, consultez Itérateurs.

Voir aussi