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.
Remarque
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
ouprivate
. Par défaut, il s’agit deprivate
. - Des modificateurs facultatifs, comme
abstract
ousealed
. - 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 elles sont différenciées par leurs types de paramètres.
Appel de méthode
Les méthodes peuvent être d’instance ou statiques. Vous devez instancier un objet pour appeler une méthode d’instance sur cette instance ; une méthode d’instance opère sur cette instance et 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. La première devient la valeur du paramètre miles
. La 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.
Collections 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 une collection de paramètres, vous permettez à votre méthode d’être appelée avec un nombre d’arguments variable. Le paramètre marqué avec le mot clé params
doit être de type collection et ce doit être le dernier paramètre de la liste des paramètres de la méthode.
Un appelant peut alors appeler la méthode de quatre façons pour le paramètre params
:
- En passant une collection du type approprié, qui contient le nombre d’éléments souhaité. L’exemple utilise une expression de collection pour que le compilateur crée un type collection approprié.
- En passant une liste d’arguments individuels séparés par des virgules et du type approprié à la méthode. Le compilateur crée le type collection approprié.
- En passant
null
. - En ne fournissant pas d’argument à la collection de paramètres.
L’exemple suivant définit une méthode nommée GetVowels
qui retourne toutes les voyelles d’une collection 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 une collection vide.
static class ParamsExample
{
static void Main()
{
string fromArray = GetVowels(["apple", "banana", "pear"]);
Console.WriteLine($"Vowels from collection expression: '{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 IEnumerable<string>? input)
{
if (input == null || !input.Any())
{
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: ''
Avant C# 13, le modificateur params
peut être utilisé seulement avec un tableau unidimensionnel.
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.
Vous affectez la valeur par défaut du paramètre avec 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écifiernull
. Vous pouvez utiliser le littéraldefault
, 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. Cette expression appelle le constructeur sans paramètre implicite du type valeur, qui n’est pas un membre réel du type.Remarque
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 au moment de la compilation. Utilisez l’expressiondefault(ValType)
ou le littéraldefault
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);
}
}
L’appelant doit fournir un argument pour tous les paramètres facultatifs jusqu’au dernier paramètre facultatif pour lequel un argument est fourni. Par exemple, dans 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, c’est-à-dire 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 correspond, par nom ou par position, à un seul argument, 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.
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 avec 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;
}
Les exemples ci-dessus sont des membres dont les corps ne comportent qu’une seule expression. Les membres dont les corps ne comportent qu’une seule expression retournent la valeur retournée par l’expression.
Vous pouvez également choisir de définir vos méthodes avec un corps d’instruction et une instruction return
:
class SimpleMathExtnsion
{
public int DivideTwoNumbers(int number1, int number2)
{
return number1 / number2;
}
}
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. Ainsi, les trois 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);
result = obj2.DivideTwoNumbers(6,2);
// The result is 3.
Console.WriteLine(result);
Vous voulez parfois que votre méthode retourne plusieurs valeurs. Vous utilisez des types tuple et des littéraux de tuple pour retourner plusieurs valeurs. 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 de famille 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é en utilisant le code suivant :
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 une méthode prend un tableau comme paramètre et qu’elle modifie la valeur d’éléments individuels, il n’est pas nécessaire que la méthode retourne le tableau. C# passe tous les types référence par valeur et la valeur d’une référence de tableau est le pointeur vers le 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. Une modification de la source crée un changement cassant 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.
Remarque
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 immédiatement avec le résultat d’une expression, ou qui ont une seule instruction comme 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.