Implémenter des méthodes et des paramètres de classe

Terminée

Une méthode est un bloc de code qui contient une série d’instructions. Un programme entraîne l’exécution des instructions en appelant la méthode et en spécifiant les arguments de méthode requis. En C#, chaque instruction est exécutée dans le contexte d’une méthode.

Signatures de méthode

Les méthodes sont déclarées dans une classe, un enregistrement ou un struct en spécifiant ce qui suit :

  • Un niveau d’accès facultatif, tel que public ou private. La valeur par défaut est private.
  • Des modificateurs facultatifs, tels que abstract ou sealed.
  • La valeur de retour, ou void si la méthode n’en a aucune.
  • Le nom de la méthode.
  • Tous les paramètres de méthode. Les paramètres de méthode sont placés entre parenthèses et sont séparés par des virgules. Les parenthèses vides indiquent que la méthode ne nécessite aucun paramètre.

Ces parties fonctionnent ensemble pour former 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 à laquelle il fait référence.

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. Les deux méthodes Drive ont le même nom, mais différents types de paramètres.

Appel de méthode

Les méthodes peuvent être des instances ou statiques. Vous devez instancier un objet pour appeler une méthode d’instance sur cette instance ; une méthode d’instance fonctionne sur cette instance et ses données. Vous appelez une méthode statique en référençant le nom du type auquel appartient la méthode ; Les méthodes statiques ne fonctionnent pas sur les données d’instance. La tentative d’appel d’une méthode statique par le biais d’une instance d’objet génère une erreur du compilateur.

L’appel d’une méthode ressemble à l’accès à un champ. Après le nom de l’objet (si vous appelez une méthode d’instance) ou le nom de type (si vous appelez une méthode statique), ajoutez un point, le nom de la méthode et des parenthèses. Les arguments sont répertoriés entre parenthèses et sont séparés par des virgules.

La définition de la méthode spécifie les noms et types des paramètres requis. Lorsqu’un appelant appelle la méthode, elle 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, s’il est utilisé dans le code appelant, n’a pas besoin d’être identique au paramètre nommé défini dans la méthode. Dans l’exemple suivant, la méthode Square inclut un paramètre unique de type int nommé i. Le premier appel de méthode transmet la méthode Square une variable de type int nommée num, le deuxième, une constante numérique et le troisième, 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;
    }
}

Paramètres de valeur et de référence

Les types en C# sont des types valeur ou des types référence. Par défaut, les types valeur et les types référence sont passés par valeur à une méthode.

Paramètres de type valeur

Lorsqu’un type valeur est passé à une méthode par valeur, une copie de l’objet au lieu de l’objet lui-même est passée à la méthode. Par conséquent, les modifications apportées à l’objet dans la méthode appelée n’ont aucun effet sur l’objet d’origine lorsque le contrôle retourne à l’appelant.

L’exemple suivant transmet un type valeur à une méthode par valeur, et la méthode appelée tente de modifier la valeur du type valeur. Elle définit une variable de type int, qui est un type valeur, initialise sa valeur à 20 et la transmet à une méthode nommée ModifyValue qui modifie la valeur de la variable sur 30. Toutefois, lorsque la méthode est retournée, la valeur de la variable reste 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

Lorsqu’un objet d’un type référence est passé à une méthode par valeur, une référence à l’objet 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 à l’aide de cette référence, la modification est reflétée dans l’objet lorsque le contrôle retourne à la méthode appelante. Toutefois, le remplacement de l’objet passé à la méthode n’a aucun effet sur l’objet d’origine lorsque le contrôle revient à l’appelant.

L’exemple suivant définit une classe (qui est un type de référence) nommée SampleRefType. Il instancie un objet SampleRefType, affecte 44 à son champ value et transmet l’objet à la méthode ModifyObject. Cet exemple fait essentiellement la même chose que l’exemple précédent (il transmet un argument par valeur à une méthode). Toutefois, le résultat est différent, car un type référence est utilisé, plutôt qu’un type valeur. La modification apportée dans ModifyObject au champ obj.value modifie également le champ value de l’argument, rt. Lorsque la méthode Main affiche la valeur de rt nous voyons qu’elle a été mise à jour vers 33, comme le montre la sortie de l’exemple.


public class SampleRefType
{
    public int value;
}

public static class ByRefTypeExample
{
    public static void Main()
    {
        var rt = new SampleRefType { value = 44 };
        Console.WriteLine("In Main, rt.value = {0}", rt.value);
        ModifyObject(rt);
        Console.WriteLine("Back in Main, rt.value = {0}", rt.value);
    }

    static void ModifyObject(SampleRefType obj)
    {
        obj.value = 33;
        Console.WriteLine("In ModifyObject, obj.value = {0}", obj.value);
    }
}
// The example displays the following output:
//      In Main, rt.value = 44
//      In ModifyObject, obj.value = 33
//      Back in Main, rt.value = 33

Paramètres de type de référence

Vous transmettez un paramètre par référence lorsque vous souhaitez modifier la valeur d’un argument dans une méthode et que vous souhaitez 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 transmettre une valeur par référence pour éviter la copie, mais toujours empêcher 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. Lorsque la valeur du paramètre est modifiée dans la méthode ModifyValue, la modification de la valeur est reflétée lorsque le contrôle revient à 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 par les paramètres passés par référence consiste à échanger les valeurs de variables. Vous passez deux variables à une méthode par référence, et la méthode échange les contenus. L’exemple suivant échange les valeurs entières.


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

Le passage d’un paramètre de type référence vous permet de modifier la valeur de la référence elle-même, plutôt que la valeur de ses éléments ou champs individuels.

Collections de paramètres

Parfois, l’exigence que vous spécifiez 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 autorisez votre méthode à être appelée avec un nombre variable d’arguments. Le paramètre marqué avec le mot clé params doit être un type de collection et doit être le dernier paramètre de la liste de paramètres de la méthode.

Un appelant peut ensuite appeler la méthode de l’une des quatre façons pour le paramètre params :

  • En passant une collection du type approprié qui contient le nombre souhaité d’éléments. L’exemple utilise une expression de collection pour que le compilateur crée un type de collection approprié.
  • En passant une liste séparée par des virgules d’arguments individuels du type approprié à la méthode. Le compilateur crée le type de 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 illustre les quatre façons d’appeler la méthode. Les appelants ne sont pas tenus de fournir des 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: ''

Remarque

Avant C# 13, le modificateur params ne peut être utilisé qu’avec un tableau unidimensionnel.

Valeurs de retour des méthodes

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 variable, d’une constante ou d’une expression qui correspond au type de retour retourne cette valeur à l’appelant de méthode. Les méthodes avec un type de retour nonvoid 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 toujours utile pour arrêter l’exécution de la méthode. Sans le mot clé return, la méthode cesse de s’exécuter lorsqu’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;
}

Cet exemple utilise des membres expression bodied pour affecter la valeur de retour des méthodes. Cette syntaxe est un raccourci pour les méthodes qui utilisent une instruction unique (expression) pour calculer la valeur de retour.

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 renvoyée par une méthode, la méthode appelante peut employer l’appel de méthode lui-même partout où une valeur du même type serait acceptée. Vous pouvez également affecter la valeur de retour à une variable. Par exemple, les trois exemples de code suivants réalisent 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);

Parfois, vous souhaitez que votre méthode retourne plus d’une valeur unique. 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 du tuple ; la méthode retourne le premier, le milieu et le nom de la famille, ainsi que l’âge, d’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 ensuite consommer le tuple retourné à l’aide du code suivant :


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

Il est également possible d’attribuer des noms aux éléments d’un tuple dans la définition du type de 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 à la méthode GetPersonalInfo peut ensuite ê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 modifie la valeur des éléments individuels, il n’est pas nécessaire que la méthode retourne le tableau. C# transmet tous les types de référence par valeur, et la valeur d’une référence de tableau est le pointeur vers le tableau.

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 instruction unique comme corps de la méthode. Il existe un raccourci de syntaxe pour définir ces méthodes à l’aide de => :


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 asynchrone, le corps de la méthode doit être une expression d’instruction (comme pour les lambdas). Pour les propriétés et les indexeurs, ils doivent être en lecture seule et vous n’utilisez pas le mot clé d’accesseur get.