Introduction

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.

Signatures de méthode

Les méthodes sont déclarées dans une class ou un struct en spécifiant le niveau d'accès comme public ou private, les modificateurs facultatifs comme abstract ou sealed, la valeur de retour, le nom de la méthode et les éventuels paramètres de méthode. Ces parties forment ensemble la signature de la méthode.

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.

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. Cette classe contient quatre méthodes :

Accès aux méthodes

L'appel d'une méthode sur un objet revient à accéder à un champ. Après le nom de l'objet, ajoutez un point, le nom de la méthode et les parenthèses. Les arguments sont répertoriés entre les parenthèses et séparés par des virgules. Les méthodes de la classe Motorcycle peuvent donc être appelées comme dans l'exemple suivant :

Paramètres de méthode et Arguments

La définition de la méthode spécifie les noms et types des paramètres requis. Quand le code appelant appelle la méthode, il fournit des valeurs concrètes appelées arguments pour chaque paramètre. Les arguments doivent être compatibles avec le type de paramètre, mais le nom de l'argument (le cas échéant) 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. Par exemple :

Passer par référence et passer par valeur

Par défaut, quand un type valeur est passé à une méthode, une copie est passée au lieu de l'objet lui-même. Ainsi, les modifications apportées à l'argument n'ont aucun effet sur la copie d'origine dans la méthode d'appel. Vous pouvez passer un type valeur par référence en utilisant le mot clé ref.

Quand un objet d'un type référence est passé à une méthode, une référence à l'objet est passée. 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 à l'aide de cette référence, la modification est répercutée dans l'argument de la méthode d'appel, même si vous passez l'objet par valeur.

Vous créez un type référence à l'aide du mot clé class, comme le montre l'exemple suivant.

Maintenant, si vous passez un objet basé sur ce type à une méthode, une référence à l'objet est passée. L'exemple suivant passe un objet de type SampleRefType à la méthode ModifyObject.

L'exemple produit essentiellement la même chose que l'exemple précédent, dans la mesure où il passe un argument par valeur à une méthode. Mais, puisqu'un type référence est utilisé, le résultat est différent. La modification apportée dans ModifyObject au champ value du paramètre, obj, modifie également le champ value de l'argument, rt, dans la méthode TestRefType. La méthode TestRefType affiche 33 en tant que sortie.

Valeurs de retour

Les méthodes peuvent retourner une valeur à l'appelant. Si le type de retour, le type répertorié avant le nom de la méthode, n'est pas void, la méthode peut retourner la valeur à l'aide du mot clé return. Une instruction avec le mot clé return suivi d'une valeur qui correspond au type de retour retourne cette valeur à l'appelant de la méthode.

La valeur peut être retournée à l'appelant par valeur ou, à compter de C# 7.0, par référence. Les valeurs sont retournées à l'appelant par référence si le mot clé ref est utilisé dans la signature de méthode et s'il suit chaque mot clé return. Par exemple, la signature de méthode suivante et l'instruction de retour indiquent que la méthode retourne un nom de variable estDistance par référence à l'appelant.

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. Les méthodes dotées d'un type de retour non void doivent utiliser le mot clé return pour retourner une valeur. Par exemple, ces deux méthodes utilisent le mot clé return pour retourner des entiers :

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 :


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.

Pour utiliser une valeur retournée par référence à partir d'une méthode, vous devez déclarer une variable ref local si vous avez l'intention de modifier sa valeur. Par exemple, si la méthode Planet.GetEstimatedDistance retourne une valeur Double par référence, vous pouvez la définir en tant que variable ref local avec du code semblable à celui-ci :

Le retour d'un tableau multidimensionnel à partir d'une méthode, M, qui modifie le contenu du tableau n'est pas nécessaire si la fonction appelante a passé le tableau à M. Vous pouvez retourner le tableau obtenu à partir de M pour bénéficier d'un style approprié ou d'un flux fonctionnel de valeurs, mais cela n'est pas nécessaire, car C# passe tous les types de référence par valeur, et la valeur d'une référence de tableau est le pointeur qui désigne le tableau. Dans la méthode M, les modifications apportées au contenu du tableau sont observables par tout code ayant une référence au tableau, comme dans l'exemple suivant.

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, et la progression dans la méthode 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.

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

Une méthode async peut avoir un type de retour Task‹TResult›, Task ou void. Le type de retour void est principalement utilisé pour définir les gestionnaires d'événements, où un type de retour void est requis. 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.

Dans l'exemple suivant, DelayAsync est une méthode async dont le type de retour est Task‹TResult›. DelayAsync a une instruction return qui retourne un entier. Ainsi, la déclaration de méthode de DelayAsync doit avoir un type de retour de Task‹int›. étant donné que le type de retour est Task‹int›, l'évaluation de l'expression await dans DoSomethingAsync produit un entier, comme le montre l'instruction suivante : int result = await delayTask.

La méthode startButton_Click est un exemple de méthode async dont le type de retour est void. étant donné que DoSomethingAsync est une méthode async, la tâche pour l'appel à DoSomethingAsync doit être attendue, comme le montre l'instruction suivante : await DoSomethingAsync();. La méthode startButton_Click doit être définie avec le modificateur async car la méthode a une expression await.

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

Définitions de corps d'expression

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 => :

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 (même chose 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 actuel dans le code est mémorisé. L'exécution redémarre à partir de cet emplacement au prochain appel de l'itérateur.

Vous appelez un itérateur depuis le code client en utilisant une instruction foreach.

Le type de retour d'un itérateur peut être IEnumerable, IEnumerable‹T›, IEnumerator ou IEnumerator‹T›.

Fonctions locales

à compter de C# 7.0, C# prend en charge les fonctions locales. Les fonctions locales sont des méthodes privées d'un type qui sont imbriqués dans un autre membre. Elles ne peuvent être appelées qu'à partir de leur membre conteneur. Les fonctions locales peuvent être déclarées et appelées dans et à partir des éléments suivants :

  • Méthodes, tout particulièrement les méthodes iterator et async
  • Constructeurs
  • Accesseurs de propriété
  • Accesseurs d'événement
  • Méthodes anonymes
  • Expressions lambda
  • Finaliseurs
  • Autres fonctions locales

En revanche, les fonctions locales ne peuvent pas être déclarées à l'intérieur d'un membre expression-bodied.

Dans certains cas, vous pouvez utiliser une expression lambda pour implémenter la fonctionnalité également prise en charge par une fonction locale.

Les fonctions locales permettent de clarifier l'objectif de votre code. Quiconque lisant votre code peut voir que la méthode ne peut pas être appelée, sauf par la méthode conteneur. Pour les projets d'équipe, elles empêchent aussi à un autre développeur d'appeler par inadvertance la méthode directement à partir d'un autre emplacement dans la classe ou le struct.

Syntaxe des fonctions locales

Une fonction locale est définie en tant que méthode imbriquée à l'intérieur d'un membre conteneur. Sa définition présente la syntaxe suivante :

Les fonctions locales peuvent utiliser les modificateurs async et unsafe.

Notez que toutes les variables locales définies dans le membre conteneur, y compris ses paramètres de méthode, sont accessibles dans la fonction locale.

Contrairement à la définition d'une méthode, la définition d'une fonction locale ne peut pas inclure les éléments suivants :

  • Le modificateur d'accès de membre. Comme toutes les fonctions locales sont privées, l'inclusion d'un modificateur d'accès, tel que le mot clé private, génère l'erreur de compilateur CS0106 : "Le modificateur "private" n'est pas valide pour cet élément".
  • Le mot clé static. L'inclusion du mot clé static génère l'erreur de compilateur CS0106 : "Le modificateur "static" n'est pas valide pour cet élément".

Par ailleurs, les attributs ne peuvent pas être appliqués à la fonction locale ou à ses paramètres et paramètres de type.

L'exemple suivant définit une fonction locale nommée AppendPathSeparator qui est privée pour une méthode nommée GetText :

Fonctions locales et exceptions

L'une des caractéristiques intéressantes des fonctions locales est qu'elles permettent l'affichage immédiat des exceptions. Pour les itérateurs de méthode, les exceptions apparaissent uniquement au moment où la séquence retournée est énumérée, et non à la récupération de l'itérateur. Pour les méthodes async, les exceptions levées dans une méthode async sont observées quand la tâche retournée est attendue.

L'exemple suivant définit une méthode OddSequence qui énumère les nombres impairs dans une plage spécifiée. Sachant qu'elle passe à la méthode d'énumérateur OddSequence un nombre supérieur à 100, la méthode lève une exception ArgumentOutOfRangeException. Comme le montre la sortie de l'exemple, l'exception apparaît uniquement au moment d'itérer les nombres, et non à la récupération de l'énumérateur.

Au lieu de cela, vous pouvez lever une exception au moment d'effectuer la validation et avant la récupération de l'itérateur en retournant l'itérateur à partir d'une fonction locale, comme dans l'exemple suivant.

Les fonctions locales peuvent être utilisées de manière similaire pour gérer les exceptions en dehors de l'opération asynchrone. D'ordinaire, les exceptions levées dans la méthode async nécessitent que vous examiniez les exceptions internes d'un AggregateException. Les fonctions locales permettent à votre code d'échouer rapidement et à votre exception d'être à la fois levée et observée de manière synchrone.

L'exemple suivant utilise une méthode asynchrone nommée GetMultipleAsync visant à marquer une pause pendant un nombre défini de secondes et retourner une valeur qui est un multiple aléatoire de ce nombre de secondes. Le délai maximal est de 5 secondes ; une exception ArgumentOutOfRangeException est obtenue si la valeur est supérieure à 5. Comme le montre l'exemple suivant, l'exception qui est levée quand une valeur de 6 est passée à la méthode GetMultipleAsync est encapsulée dans une exception AggregateException après que la méthode GetMultipleAsync a démarré son exécution.

Comme nous l'avons fait avec l'itérateur de méthode, nous pouvons refactoriser le code de cet exemple pour assurer la validation avant l'appel de la méthode asynchrone. Comme le montre la sortie de l'exemple suivant, l'exception ArgumentOutOfRangeException n'est pas encapsulée dans une exception AggregateException.


Retours ref et variables locales ref

à compter de C# 7.0, C# prend en charge les valeurs de retour de référence (retours ref). Une valeur de retour de référence permet à une méthode de retourner à un appelant une référence à une variable, plutôt qu'à une valeur. L'appelant peut alors 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 nouvelle variable qui est elle-même une référence à la valeur retournée, appelée variable locale ref.

Qu'est-ce qu'une valeur de retour de référence ?

La plupart des développeurs sont familiarisés avec le passage d'un argument à une méthode appelée par référence. La liste d'arguments d'une méthode appelée inclut une variable passée par référence. Chaque modification de sa valeur par la méthode appelée est respectée par l'appelant. 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. Des modifications apportées par l'appelant à la valeur de retour de la méthode portent sur la variable qui est 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 vers une variable. L'intention de conception est souvent que le code appelant ait accès à cette variable à travers l'alias, et qu'il puisse également la modifier. C'est pourquoi les méthodes de retour par référence ne peuvent pas avoir le type de retour void.

Certaines restrictions s'appliquent à l'expression qu'une méthode peut retourner comme valeur de retour de référence. Les restrictions sont les suivantes :

  • 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'un champ d'instance ou statique d'une classe, ou bien un argument passé à la méthode. Une tentative de retour d'une variable locale génère l'erreur du compilateur CS8168, "Impossible de retourner la variable locale 'obj' par référence, car il ne s'agit pas d'une variable locale de référence".
  • La valeur de retour ne peut pas être le littéral null. Le retour de null génère l'erreur de compilateur CS8156, "Impossible d'utiliser une expression dans ce contexte, car elle ne peut pas être retournée par référence". Une méthode avec un retour de référence peut retourner un alias vers une variable dont la valeur est actuellement la valeur (non instanciée) null ou un type 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'une class ou d'un struct. Le non-respect de cette règle génère l'erreur de compilateur CS8156, "Impossible d'utiliser une expression dans ce contexte, car elle ne peut pas être retournée par référence".

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 être retournée avant la fin de son exécution, même si sa valeur de retour est encore inconnue.

Définition d'une valeur de retour de référence

Une méthode qui retourne une valeur de retour de référence doit remplir les deux conditions suivantes :

  • Dans la signature de méthode, le mot clé ref précède le type de retour.
  • Pour chaque instruction return dans le corps de la méthode, le mot clé ref précède le nom de l'instance retournée.

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

Utilisation d'une valeur de retour de référence

La valeur de retour de référence est l'alias vers une autre variable dans l'étendue de la méthode appelée. Toute utilisation d'une valeur de retour de référence revient à utiliser la variable dont elle est l'alias :

  • Quand vous lui affectez une valeur, vous affectez une valeur à la variable dont elle est l'alias.
  • Quand vous lisez sa valeur, vous lisez la valeur de la variable dont elle est l'alias.
  • Si vous la retournez par référence, vous retournez un alias vers cette même variable.
  • Si vous la passez à une autre méthode par référence, vous passez une référence à la variable dont elle est l'alias.
  • Quand vous créez un alias de variable locale ref, vous créez un nouvel alias vers la même variable.

Variables locales ref

Partez du principe que la méthode GetContactInformation est déclarée comme un retour de référence :

Une affectation par valeur lit la valeur d'une variable et l'affecte à une nouvelle variable :

L'affectation précédente déclare p comme une variable locale. Sa valeur initiale est copiée à partir de la lecture de la valeur retournée par GetContactInformation. Toute affectation future à p ne modifiera en rien la valeur de la variable renvoyée par GetContactInformation. La variable p n'est plus un alias vers la variable retournée.

Vous déclarez une variable locale ref pour copier l'alias vers la valeur d'origine. Dans l'affectation suivante, p est un alias vers la variable retournée à partir de GetContactInformation.

L'utilisation ultérieure de p revient à utiliser la variable retournée par GetContactInformation, car p est un alias de cette variable. Les modifications apportées à p modifient également la variable retournée à partir de GetContactInformation.

Le mot clé ref est utilisé à la fois avant la déclaration de la variable locale et avant l'appel de la méthode.

Vous pouvez accéder à une valeur par référence de la même façon. Dans certains cas, l'accès à une valeur par référence augmente les performances en évitant une opération de copie potentiellement coûteuse. Par exemple, l'instruction suivante montre comment il est possible de définir une valeur locale ref qui est utilisée pour référencer une valeur.

Le mot clé ref est utilisé à la fois avant la déclaration de la variable locale et avant la valeur du second exemple. Si les deux mots clés ref ne sont pas inclus dans la déclaration et l'affectation de la variable dans les deux exemples, l'erreur du compilateur CS8172, "Impossible d'initialiser une variable par référence avec une valeur" est générée.

Dans les versions antérieures à C# 7.3, les variables locales ref ne pouvaient pas être réassignées pour référencer un stockage différent après avoir été initialisées. Cette restriction a été supprimée. L'exemple suivant illustre une réassignation :

Les variables locales ref doivent toujours être initialisées quand elles sont déclarées.

Retours ref et variables locales ref : exemple

L'exemple suivant définit une classe NumberStore qui stocke un tableau de valeurs entières. La méthode FindNumber retourne par référence le premier nombre supérieur ou égal au nombre passé comme argument. Si aucun nombre n'est supérieur ou égal à l'argument, la méthode retourne le nombre se trouvant à l'index 0.

L'exemple suivant appelle la méthode NumberStore.FindNumber pour récupérer la première valeur supérieure ou égale à 16. L'appelant multiplie ensuite par deux la valeur retournée par la méthode. La sortie de l'exemple montre comment la modification est reflétée dans la valeur des éléments de tableau de l'instance NumberStore.

Si les valeurs de retour de référence ne sont pas prises en charge, une telle opération est effectuée en retournant l'index de l'élément de tableau ainsi que sa valeur de retour. L'appelant peut ensuite utiliser cet index pour modifier la valeur dans un appel de méthode distinct. Toutefois, l'appelant peut également modifier l'index pour accéder à d'autres valeurs de tableau et éventuellement les modifier.

L'exemple suivant montre comment réécrire la méthode FindNumber à compter de C# 7.3 pour utiliser la réassignation des variables locales ref :

Cette deuxième version est plus efficace avec des séquences plus longues dans les scénarios où le nombre recherché est proche de la fin du tableau.


Passage de paramètres

En C#, les arguments peuvent être passés aux paramètres par valeur ou par référence. Avec le passage par référence, les fonctions membres, les méthodes, les propriétés, les indexeurs, les opérateurs et les constructeurs peuvent changer la valeur des paramètres et rendre cette modification persistante dans l'environnement d'appel. Pour passer un paramètre par référence avec l'intention de changer la valeur, utilisez le mot clé ref ou out. Pour passer un paramètre par référence avec l'intention d'éviter la copie, mais de ne pas changer la valeur, utilisez le modificateur in. Pour plus de simplicité, les exemples de cette rubrique utilisent uniquement le mot clé ref. Pour plus d'informations sur la différence entre in, ref et out, consultez in, ref et out.

L'exemple suivant illustre la différence entre les paramètres de référence et de valeur.


Passage de paramètres de type valeur

Une variable de type valeur contient ses données directement, par opposition à une variable de type référence, qui contient une référence à ses données. Passer une variable de type valeur à une méthode par valeur signifie passer une copie de la variable à la méthode. Les modifications du paramètre qui interviennent à l'intérieur de la méthode n'ont aucune incidence sur les données d'origine stockées dans la variable d'argument. Si vous souhaitez que la méthode appelée change la valeur du paramètre, vous devez la passer par référence, à l'aide du mot clé ref ou out. Vous pouvez également utiliser le mot clé in pour passer un paramètre de valeur par référence et éviter la copie tout en garantissant que la valeur n'est pas changée. Pour des raisons de simplicité, les exemples suivants utilisent ref.

Passage de types valeur par valeur

L'exemple suivant illustre le passage de paramètres de type valeur par valeur. La variable n est passée par valeur à la méthode SquareIt. Les modifications qui interviennent à l'intérieur de la méthode n'ont aucune incidence sur la valeur d'origine de la variable.

La variable n est un type valeur. Elle contient ses données, la valeur 5. Quand SquareIt est appelée, le contenu de n est copié dans le paramètre x, qui est mis au carré à l'intérieur de la méthode. Dans Main, toutefois, la valeur de n est identique avant et après l'appel de la méthode SquareIt. La modification qui intervient à l'intérieur de la méthode affecte uniquement la variable locale x.

Passage de types valeur par référence

L'exemple suivant est identique au précédent, sauf que l'argument est passé en tant que paramètre ref. La valeur de l'argument sous-jacent, n, est modifiée quand x est modifiée dans la méthode.

Dans cet exemple, ce n'est pas la valeur de n qui est passée, mais plutôt une référence à n. Le paramètre x n'est pas un int ; il s'agit d'une référence à un int, dans le cas présent une référence à n. Ainsi, quand x est mis au carré à l'intérieur de la méthode, ce qui est réellement mis au carré est ce à quoi x fait référence, c'est-à-dire n.

Permutation de types valeur

L'un des exemples courants de changement de valeurs d'arguments est une méthode de permutation, où vous passez deux variables à la méthode et celle-ci permute leur contenu. Vous devez passer les arguments à la méthode de permutation par référence. Sinon, vous permutez des copies locales des paramètres à l'intérieur de la méthode, et aucune modification n'intervient dans la méthode d'appel. L'exemple suivant permute des valeurs d'entier.

Quand vous appelez la méthode SwapByRef, utilisez le mot-clé ref dans l'appel, comme illustré dans l'exemple suivant.


Passage de paramètres de type référence

Une variable d'un type référence ne contient pas directement ses données ; il contient une référence à ses données. Quand vous passez un paramètre de type référence par valeur, il est possible de changer les données appartenant à l'objet référencé, comme la valeur d'un membre de classe. En revanche, vous ne pouvez pas changer la valeur de la référence elle-même. Par exemple, vous ne pouvez pas utiliser la même référence pour allouer de la mémoire à une nouvelle classe et la faire persister en dehors de la méthode. Pour cela, passez le paramètre en utilisant le mot clé ref ou out. Pour des raisons de simplicité, les exemples suivants utilisent ref.

Passage de types référence par valeur

L'exemple suivant illustre le passage d'un paramètre de type référence (arr) par valeur, à une méthode (Change). Sachant que le paramètre est une référence à arr, il est possible de modifier les valeurs des éléments du tableau. Cependant, la tentative de réassignation du paramètre à un emplacement de mémoire différent n'aboutit qu'à l'intérieur de la méthode et n'affecte pas la variable d'origine, arr.

Dans l'exemple précédent, le tableau arr, qui est un type référence, est passé à la méthode sans le paramètre ref. Dans ce cas, une copie de la référence, qui pointe vers arr, est passée à la méthode. La sortie montre que la méthode peut modifier le contenu d'un élément du tableau, dans ce cas de 1 à 888. Cependant, si vous allouez une nouvelle portion de mémoire via l'opérateur new à l'intérieur de la méthode Change, la variable pArray fait référence à un nouveau tableau. Par conséquent, les modifications apportées à la suite de cette opération n'ont pas d'effet sur le tableau d'origine (arr), qui est créé à l'intérieur de Main. En fait, deux tableaux sont créés dans cet exemple : un à l'intérieur de Main et un autre à l'intérieur de la méthode Change.

Passage de types référence par référence

L'exemple suivant est identique au précédent, sauf que le mot clé ref est ajouté à l'en-tête et à l'appel de la méthode. Les modifications qui se produisent dans la méthode affectent la variable d'origine dans le programme appelant.

Les modifications qui se produisent à l'intérieur de la méthode affectent le tableau d'origine dans Main. En fait, le tableau d'origine est réalloué à l'aide de l'opérateur new. Par conséquent, après l'appel à la méthode Change, toute référence à arr pointe vers le tableau à cinq éléments, qui est créé dans la méthode Change.

Permutation de deux chaînes

La permutation de chaînes est un bon exemple de passage de paramètres de type référence par référence. Dans l'exemple, deux chaînes, str1 et str2, sont initialisées dans Main et passées à la méthode SwapStrings en tant que paramètres modifiés par le mot clé ref. Les deux chaînes sont permutées à l'intérieur de la méthode mais aussi à l'intérieur de Main.

Dans cet exemple, les paramètres doivent être passés par référence pour affecter les variables dans le programme appelant. Si vous supprimez le mot clé ref de l'en-tête et de l'appel de la méthode, aucune modification ne se produit dans le programme appelant.

Différencier le passage d'un struct et le passage d'une référence de classe à une méthode

L'exemple suivant montre comment le passage d'un struct à une méthode diffère du passage d'une instance de classe à une méthode. Dans l'exemple, les deux arguments (struct et instance de classe) sont passés par valeur, tandis que les deux méthodes changent la valeur d'un champ de l'argument. Toutefois, les résultats des deux méthodes ne sont pas identiques, car ce qui est passé quand vous passez un struct diffère de ce qui est passé quand vous passez une instance d'une classe.

étant donné qu'un struct est un type valeur, quand vous passez un struct par valeur à une méthode, la méthode reçoit et traite une copie de l'argument struct. La méthode n'a pas accès au struct d'origine dans la méthode d'appel, et ne peut donc pas le modifier de quelque manière que ce soit. La méthode peut modifier uniquement la copie.

Une instance de classe est un type référence, pas un type valeur. Quand un type référence est passé par valeur à une méthode, celle-ci reçoit une copie de la référence à l'instance de classe. Autrement dit, la méthode reçoit une copie de l'adresse de l'instance, et non pas une copie de l'instance elle-même. L'instance de classe dans la méthode d'appel a une adresse, le paramètre dans la méthode appelée a une copie de l'adresse, et les deux adresses font référence au même objet. étant donné que le paramètre contient uniquement une copie de l'adresse, la méthode appelée ne peut pas modifier l'adresse de l'instance de la classe dans la méthode. Toutefois, la méthode appelée peut utiliser l'adresse pour accéder aux membres de classe qui font à la fois référence à l'adresse d'origine et à la copie. Si la méthode appelée modifie un membre de classe, l'instance de classe d'origine dans la méthode d'appel change également.

La sortie de l'exemple suivant illustre la différence. La valeur du champ willIChange de l'instance de classe est changée par l'appel à la méthode ClassTaker, car la méthode utilise l'adresse mentionnée dans le paramètre pour rechercher le champ spécifié de l'instance de classe. Le champ willIChange du struct de la méthode d'appel n'est pas changé par l'appel à la méthode StructTaker, car la valeur de l'argument est une copie du struct lui-même, et non pas une copie de son adresse. StructTaker change la copie, et cette dernière est perdue quand l'appel à StructTaker est terminé.


Variables locales implicitement typées

Les variables locales peuvent être déclarées sans donner de type explicite. Le mot clé var indique au compilateur de déduire le type de la variable à partir de l'expression située à droite de l'instruction d'initialisation. Le type déduit peut être un type intégré, un type anonyme, un type défini par l'utilisateur ou un type défini dans la bibliothèque de classes .NET Framework. Pour plus d'informations sur l'initialisation des tableaux avec var, consultez Tableaux implicitement typés.

Les exemples suivants montrent différentes manières de déclarer des variables locales avec var :

Il est important de comprendre que le mot clé var n'est pas "variant" et qu'il n'indique pas que la variable est peu typée ou à liaison tardive. Cela signifie simplement que le compilateur détermine et assigne le type qui convient le mieux.

Le mot clé var peut être utilisé dans les contextes suivants :

Dans des variables locales (variables déclarées dans la portée de la méthode), comme indiqué dans l'exemple précédent.

Dans une instruction d'initialisation for

Dans une instruction d'initialisation foreach

Dans une instruction using

Types var et anonymes

Dans de nombreux cas, l'utilisation de var est facultative et sert uniquement à simplifier la syntaxe. Toutefois, lorsqu'une variable est initialisée avec un type anonyme, vous devez déclarer la variable en tant que var si vous savez déjà que vous aurez besoin d'accéder aux propriétés de l'objet. Il s'agit d'un scénario courant avec les expressions de requête LINQ. Pour plus d'informations, consultez Types anonymes.

Du point de vue de votre code source, un type anonyme n'a pas de nom. Par conséquent, si une variable de requête a été initialisée avec var, la seule façon d'accéder aux propriétés de la séquence d'objets retournée consiste à utiliser var comme type pour la variable d'itération de l'instruction foreach.

Notes

Les restrictions suivantes s'appliquent aux déclarations de variables implicitement typées :

  • var peut être utilisé uniquement lorsqu'une variable locale est déclarée et initialisée dans la même instruction. La variable ne peut pas être initialisée vers la valeur Null, vers un groupe de méthodes ou vers une fonction anonyme.
  • var ne peut pas être utilisé dans les champs situés dans la portée de la classe.
  • Les variables déclarées à l'aide de var ne peuvent pas être utilisées dans l'expression d'initialisation. En d'autres termes, l'expression : int i = (i = 20); est légale, mais l'expression var i = (i = 20); génère une erreur de compilation.
  • Il n'est pas possible d'initialiser plusieurs variables implicitement typées dans la même instruction.
  • Si un type nommé var se trouve dans la portée, le mot clé var est résolu en ce nom de type et n'est pas considéré comme faisant partie d'une déclaration de variable locale implicitement typée.

var peut également être utile avec les expressions de requête dans lesquelles il est difficile de déterminer le type construit exact de la variable de requête. Cela peut se produire avec les opérations de regroupement et de classement.

Le mot clé var peut également être utile lorsque le type de la variable est fastidieux à taper, ou bien lorsqu'il est évident ou lorsqu'il n'aide pas à la lisibilité du code. Par exemple, var est utile avec les types génériques imbriqués tels que ceux utilisés avec les opérations de groupe. Dans la requête suivante, le type de la variable de requête est IEnumerable>. Tant que les personnes qui doivent gérer votre code comprennent ceci, le typage implicite peut tout à fait être utilisé pour rendre votre code plus concis et simplifier sa gestion.

Toutefois, l'utilisation de var risque de rendre votre code plus difficile à comprendre pour les autres développeurs. C'est pourquoi, en général, la documentation C# utilise var uniquement lorsque cela est nécessaire.


Utiliser des tableaux et des variables locales implicitement typés dans une expression de requête

Vous pouvez utiliser des variables locales implicitement typées chaque fois que vous voulez que le compilateur détermine le type d'une variable locale. Vous devez utiliser des variables locales implicitement typées pour stocker des types anonymes, qui sont souvent utilisés dans les expressions de requête. Les exemples suivants illustrent des utilisations facultatives et obligatoires de variables locales implicitement typées dans des requêtes.

Les variables locales implicitement typées sont déclarées à l'aide du mot clé contextuel var. Pour plus d'informations, consultez Variables locales implicitement typées et Tableaux implicitement typés.

Exemple

L'exemple suivant illustre un scénario courant dans lequel le mot clé var est obligatoire : une expression de requête qui produit une séquence de types anonymes. Dans ce scénario, la variable de requête et la variable d'itération figurant dans l'instruction foreach doivent être implicitement typées avec var, car vous n'avez pas accès à un nom de type pour le type anonyme. Pour plus d'informations sur les types anonymes, consultez Types anonymes.

Dans l'exemple suivant, le mot clé var est utilisé dans un cas similaire, à la différence que l'utilisation de var est facultative. Comme student.LastName est une chaîne, l'exécution de la requête retourne une séquence de chaînes. De ce fait, le type de queryID pourrait être déclaré en tant que System.Collections.Generic.IEnumerable au lieu de var. Le mot clé var est utilisé pour des raisons pratiques. Dans l'exemple, la variable d'itération figurant dans l'instruction foreach est explicitement typée en tant que chaîne, mais elle aurait pu être déclarée à l'aide de var. Comme le type de la variable d'itération n'est pas un type anonyme, l'utilisation de var est facultative et non obligatoire. Pour rappel, var n'est pas en soi un type, mais une instruction indiquant au compilateur de déduire et d'assigner le type.


Méthodes d'extension

Les méthodes d'extension vous permettent d'ajouter des méthodes à des types existants sans créer un type dérivé, ni recompiler ou modifier le type d'origine. Les méthodes d'extension sont un type particulier de méthode statique appelées comme s'il s'agissait de méthodes d'instance sur le type étendu. Pour le code client écrit en C#, F# et Visual Basic, il n'y a aucune différence apparente lors de l'appel entre une méthode d'extension et les méthodes qui sont réellement définies dans un type.

Les méthodes d'extension les plus courantes sont les opérateurs de requête standard LINQ qui ajoutent des fonctionnalités de requête aux types System.Collections.IEnumerable et System.Collections.Generic.IEnumerable existants. Pour utiliser les opérateurs de requête standard, introduisez-les d'abord dans la portée avec une directive using System.Linq. Puis, tout type qui implémente IEnumerable semble avoir des méthodes d'instance telles que GroupBy, OrderBy, Average, etc. Vous pouvez consulter ces méthodes supplémentaires dans la saisie semi-automatique des instructions IntelliSense quand vous tapez un "point" après une instance d'un type IEnumerable tel que List ou Array.

L'exemple suivant indique comment appeler la méthode OrderBy d'opérateur de requête standard sur un tableau d'entiers. L'expression entre parenthèses est une expression lambda. De nombreux opérateurs de requête standard prennent des expressions lambda comme paramètres, mais ce n'est pas requis pour les méthodes d'extension. Pour plus d'informations, consultez Expressions lambda.

Les méthodes d'extension sont définies comme méthodes statiques mais sont appelées en utilisant la syntaxe de méthode d'instance. Leur premier paramètre spécifie les types sur lesquels la méthode s'applique et le paramètre est précédé du modificateur this. Les méthodes d'extension sont uniquement dans la portée lorsque vous importez explicitement l'espace de noms dans votre code source avec une directive using.

L'exemple suivant présente une méthode d'extension définie pour la classe System.String. Notez qu'elle est définie à l'intérieur d'une classe statique, non imbriquée et non générique :

La méthode d'extension WordCount peut être mise à portée avec cette directive using :

Elle peut être appelée à partir d'une application à l'aide de cette syntaxe :

Dans votre code, vous appelez la méthode d'extension avec la syntaxe de méthode d'instance. Toutefois, le langage intermédiaire (IL) généré par le compilateur traduit votre code dans un appel sur la méthode statique. Par conséquent, le principe d'encapsulation n'est pas réellement violé. En fait, les méthodes d'extension ne peuvent pas accéder aux variables privées dans le type qu'elles étendent.

Pour plus d'informations, voir Procédure : Implémenter et appeler une méthode d'extension personnalisée.

En général, vous appellerez probablement les méthodes d'extension beaucoup plus souvent que vous n'implémenterez vos propres méthodes. Comme les méthodes d'extension sont appelées à l'aide de la syntaxe de méthode d'instance, aucune connaissance particulière n'est requise pour les utiliser depuis le code client. Pour activer des méthodes d'extension pour un type particulier, ajoutez simplement une directive using pour l'espace de noms dans lequel les méthodes sont définies. Par exemple, pour utiliser les opérateurs de requête standard, ajoutez la directive using à votre code :

(Il peut également être nécessaire d'ajouter une référence à System.Core.dll.) Vous pouvez remarquer que les opérateurs de requête standard apparaissent dorénavant dans IntelliSense comme des méthodes supplémentaires disponibles pour la plupart des types IEnumerable.

Liaison de méthodes d'extension à la compilation

Vous pouvez utiliser des méthodes d'extension pour étendre une classe ou une interface, mais pas pour les remplacer. Une méthode d'extension avec le même nom et la même signature qu'une méthode d'interface ou de classe ne sera jamais appelée. Au moment de la compilation, les méthodes d'extension ont toujours la priorité la plus faible par rapport aux méthodes d'instance définies dans le type lui-même. En d'autres termes, si un type a une méthode nommée Process(int i) et que vous avez une méthode d'extension avec la même signature, le compilateur créera toujours une liaison avec la méthode d'instance. Lorsque le compilateur rencontre un appel de méthode, il recherche d'abord une correspondance dans les méthodes d'instance du type. Si aucune correspondance n'est trouvée, il recherche toutes les méthodes d'extension définies pour le type et crée une liaison avec la première méthode d'extension qu'il trouve. L'exemple suivant montre comment le compilateur détermine quelle méthode d'extension ou méthode d'instance est choisie pour créer une liaison.

Exemple

L'exemple suivant montre les règles que le compilateur C# suit pour déterminer s'il faut lier un appel de méthode à une méthode d'instance sur le type, ou à une méthode d'extension. Le classe statique Extensions contient des méthodes d'extension définies pour tout type qui implémente IMyInterface. Les classes A, B et C implémentent toutes l'interface.

La méthode d'extension MethodB n'est jamais appelée car son nom et sa signature correspondent exactement aux méthodes déjà implémentées par les classes.

Lorsque le compilateur ne trouve pas de méthode d'instance avec une signature correspondante, il crée une liaison avec une méthode d'extension correspondante, s'il en existe une.

Indications générales

En général, nous vous recommandons d'implémenter des méthodes d'extension modérément et uniquement lorsque cela est nécessaire. Dès que cela est possible, le code client qui doit étendre un type existant doit le faire en créant un type dérivé du type existant. Pour plus d'informations, consultez Héritage.

Lors de l'utilisation d'une méthode d'extension pour étendre un type dont le code source ne peut pas être modifié, vous risquez d'interrompre votre méthode d'extension en cas de modification dans l'implémentation du type.

Si vous implémentez des méthodes d'extension pour un type donné, prenez en compte les points suivants :

  • Une méthode d'extension ne sera jamais appelée si elle a la même signature qu'une méthode définie dans le type.
  • Les méthodes d'extension sont mises en portée au niveau de l'espace de noms. Par exemple, si vous avez plusieurs classes statiques qui contiennent des méthodes d'extension dans un espace de noms unique nommé Extensions, elles seront toutes mises en portée par la directive using Extensions;.

Pour une bibliothèque de classes que vous avez implémentée, vous ne devez pas utiliser de méthodes d'extension pour éviter d'incrémenter le numéro de version d'un assembly. Si vous souhaitez ajouter une fonctionnalité importante à une bibliothèque dont le code source vous appartient, vous devez suivre les directives .NET Framework standard relatives à la gestion de version des assemblys. Pour plus d'informations, consultez Versioning des assemblys.


Implémenter et appeler une méthode d'extension personnalisée

Cette rubrique montre comment implémenter vos propres méthodes d'extension pour n'importe quel type .NET. Le code client peut utiliser vos méthodes d'extension en ajoutant une référence à la DLL qui les contient, et en ajoutant une directive using qui spécifie l'espace de noms dans lequel les méthodes d'extension sont définies.

Pour définir et appeler la méthode d'extension

  • Définissez une classe statique pour contenir la méthode d'extension. La classe doit être visible par le code client. Pour plus d'informations sur les règles d'accessibilité, consultez Modificateurs d'accès.
  • Implémentez la méthode d'extension en tant que méthode statique avec au moins la même visibilité que la classe conteneur.
  • Le premier paramètre de la méthode spécifie le type sur lequel la méthode opère. Il doit être précédé du modificateur this.
  • Dans le code appelant, ajoutez une directive using pour spécifier l'espace de noms qui contient la classe de méthode d'extension.
  • Appelez les méthodes comme s'il s'agissait de méthodes d'instance sur le type.

    Notez que le premier paramètre n'est pas spécifié par le code appelant, car il représente le type sur lequel l'opérateur est appliqué, et le compilateur connaît déjà le type de votre objet. Vous devez fournir des arguments uniquement pour les paramètres 2 à n.

Exemple

L'exemple suivant implémente une méthode d'extension nommée WordCount dans la classe CustomExtensions.StringExtension. La méthode opère sur la classe String, qui est spécifiée comme premier paramètre de méthode. L'espace de noms CustomExtensions est importé dans l'espace de noms d'application, et la méthode est appelée à l'intérieur de la méthode Main.

Compilation du code

Pour exécuter ce code, copiez et collez-le dans un projet d'application console Visual C# qui a été créé dans Visual Studio. Par défaut, ce projet cible la version 3.5 du .NET Framework, et il a une référence à System.Core.dll et une directive using pour System.Linq. Si un ou plusieurs de ces éléments sont manquants dans le projet, vous pouvez les ajouter manuellement.

Sécurité .NET Framework

Les méthodes d'extension ne présentent aucune faille de sécurité spécifique. Elles ne peuvent jamais être utilisées pour emprunter l'identité des méthodes existantes sur un type, car toutes les collisions de noms sont résolues en faveur de l'instance ou de la méthode statique définie par le type lui-même. Les méthodes d'extension ne peuvent pas accéder à des données privées dans la classe étendue.


Créer une méthode pour une énumération

Vous pouvez utiliser des méthodes d'extension pour ajouter des fonctionnalités propres à un type enum particulier.

Exemple

Dans l'exemple suivant, l'énumération Grades représente les notes qu'un étudiant peut obtenir dans une classe. Une méthode d'extension nommée Passing est ajoutée au type Grades pour que chaque instance de ce type "sache" maintenant si elle représente une note au-dessus de la moyenne.

Notez que la classe Extensions contient également une variable statique qui est mise à jour de manière dynamique, et que la valeur de retour de la méthode d'extension reflète la valeur actuelle de cette variable. Cela démontre que, dans les coulisses, les méthodes d'extension sont appelées directement sur la classe statique dans laquelle elles sont définies.

Compilation du code

Pour exécuter ce code, copiez et collez-le dans un projet d'application console Visual C# qui a été créé dans Visual Studio. Par défaut, ce projet cible la version 3.5 du .NET Framework, et il a une référence à System.Core.dll et une directive using pour System.Linq. Si un ou plusieurs de ces éléments sont manquants dans le projet, vous pouvez les ajouter manuellement.


Arguments nommés et facultatifs

C# 4 introduit des arguments nommés et facultatifs. Les arguments nommés vous permettent de spécifier un argument pour un paramètre particulier en associant l'argument avec le nom du paramètre plutôt qu'avec la position du paramètre dans la liste de paramètres. Les arguments facultatifs vous permettent d'omettre des arguments pour certains paramètres. Les deux techniques peuvent être utilisées avec les méthodes, les indexeurs, les constructeurs et les délégués.

Quand vous utilisez des arguments nommés et facultatifs, ils sont évalués selon leur ordre d'affichage dans la liste d'arguments, et non dans la liste de paramètres.

La combinaison de paramètres nommés et facultatifs vous permet de fournir des arguments uniquement pour certains paramètres d'une liste de paramètres facultatifs. Cette fonctionnalité facilite considérablement les appels aux interfaces COM telles que les API Microsoft Office Automation.

Arguments nommés

Avec les arguments nommés, vous n'avez plus à mémoriser ou à rechercher l'ordre des paramètres dans les listes de paramètres des méthodes appelées. Vous pouvez spécifier le paramètre de chaque argument par son nom. Par exemple, une fonction qui imprime les détails d'une commande (par exemple, le nom du vendeur, le nom du produit et le numéro de commande) peut être appelée de manière standard en envoyant des arguments par position, dans l'ordre défini par la fonction.

PrintOrderDetails("Gift Shop", 31, "Red Mug");

Si vous ne vous souvenez pas de l'ordre des paramètres, mais que vous connaissez leur nom, vous pouvez envoyer les arguments dans n'importe quel ordre.

PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop");

PrintOrderDetails(productName: "Red Mug", sellerName: "Gift Shop", orderNum: 31);

Les arguments nommés améliorent également la lisibilité de votre code en identifiant ce que chaque argument représente. Dans l'exemple de méthode ci-dessous, sellerName ne peut pas être une valeur Null ou un espace blanc. sellerName et productName étant tous deux des types de chaînes, au lieu d'envoyer les arguments par position, il est plus logique d'utiliser des arguments nommés pour lever l'ambiguïté entre les deux et réduire les risques de confusion pour toute personne lisant le code.

Les arguments nommés, quand ils sont utilisés avec des arguments de position, sont valides tant que :

  • Ils ne sont pas suivis d'arguments de position, ou
    PrintOrderDetails("Gift Shop", 31, productName: "Red Mug");

  • à compter de C# 7.2, ils sont utilisés dans la position correcte Dans l'exemple ci-dessous, le paramètre orderNum est à la position correcte, mais il n'est pas explicitement nommé.
    PrintOrderDetails(sellerName: "Gift Shop", 31, productName: "Red Mug");

Toutefois, les arguments nommés qui ne sont pas dans l'ordre ne sont pas valides s'ils sont suivis d'arguments de position.

Exemple

Le code suivant implémente les exemples de cette section, ainsi que d'autres exemples.

Arguments facultatifs

La définition d'une méthode, d'un constructeur, d'un indexeur ou d'un délégué peut spécifier que ses paramètres sont obligatoires ou facultatifs. Chaque appel doit fournir des arguments pour tous les paramètres obligatoires, mais peut omettre les arguments des paramètres facultatifs.

Dans sa définition, chaque paramètre facultatif a une valeur par défaut. Si aucun argument n'est envoyé pour ce paramètre, la valeur par défaut est utilisée. Une valeur par défaut doit être l'un des types d'expressions suivants :

  • une expression constante ;
  • une expression de la forme new ValType(), où ValType est un type valeur (par exemple, enum ou struct) ;
  • une expression de la forme default(ValType), où ValType est un type valeur.

Les paramètres facultatifs sont définis à la fin de la liste de paramètres, après tous les paramètres obligatoires. Si l'appelant fournit un argument pour l'un des paramètres d'une série de paramètres facultatifs, il doit fournir des arguments pour tous les paramètres facultatifs précédents. Les intervalles séparés par des virgules ne sont pas autorisés dans la liste d'arguments. Par exemple, dans le code suivant, la méthode d'instance ExampleMethod est définie avec un paramètre obligatoire et deux paramètres facultatifs.

L'appel suivant à ExampleMethod provoque une erreur du compilateur, car un argument est fourni pour le troisième paramètre, mais pas pour le deuxième.

//anExample.ExampleMethod(3, ,4);

Toutefois, si vous connaissez le nom du troisième paramètre, vous pouvez utiliser un argument nommé pour effectuer la tâche.

anExample.ExampleMethod(3, optionalint: 4);

IntelliSense indique les paramètres facultatifs par des crochets, comme illustré dans l'exemple suivant.

------ img

Paramètres facultatifs dans ExampleMethod

Vous pouvez aussi déclarer des paramètres facultatifs à l'aide de la classe OptionalAttribute .NET. Les paramètres OptionalAttribute ne nécessitent pas de valeur par défaut.


Exemple

Dans l'exemple suivant, le constructeur associé à ExampleClass a un seul paramètre, qui est facultatif. La méthode d'instance ExampleMethod a un paramètre obligatoire (required) et deux paramètres facultatifs (optionalstr et optionalint). Le code dans Main montre les différentes façons dont le constructeur et la méthode peuvent être appelés.

Interfaces COM

Avec la prise en charge des objets dynamiques et d'autres améliorations, les arguments nommés et facultatifs améliorent nettement l'interopérabilité avec les API COM, telles que les API Office Automation.

Par exemple, la méthode AutoFormat de l'interface Range de Microsoft Office Excel comporte sept paramètres, tous facultatifs. Ces paramètres sont indiqués dans l'illustration suivante.

----- img

Paramètres AutoFormat

Dans C# 3.0 et les versions antérieures, un argument est obligatoire pour chaque paramètre, comme indiqué dans l'exemple suivant.

Toutefois, vous pouvez considérablement simplifier l'appel à AutoFormat en utilisant les arguments nommés et facultatifs introduits dans C# 4.0. Les paramètres nommés et facultatifs vous permettent d'omettre l'argument d'un paramètre obligatoire si vous ne souhaitez pas modifier la valeur par défaut du paramètre. Dans l'appel suivant, une valeur est spécifiée pour un seul des sept paramètres.

Pour obtenir plus d'informations et d'exemples, consultez Guide pratique pour utiliser des arguments nommés et facultatifs dans la programmation Office et Guide pratique pour accéder aux objets Office Interop à l'aide des fonctionnalités Visual C#.

Résolution de surcharge

L'utilisation d'arguments nommés et facultatifs affecte la résolution de surcharge des manières suivantes :

  • 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 son nom ou sa 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 s'explique par l'application d'une préférence générale dans la résolution de surcharge en faveur des candidats qui ont le moins de paramètres.