Aller au contenu

Méthodes avec retour de plusieurs valeurs

"Pourquoi se contenter d’une seule réponse quand on peut en avoir plusieurs ?"

Un développeur curieux

Qu’est-ce qu’une méthode avec retour multiple ?

Depuis C# 7, une méthode peut retourner plusieurs valeurs sans utiliser out ou des classes/structures.

➡️ Cela est rendu possible grâce aux tuples ((type1, type2, …)).

💡 Les tuples permettent de regrouper plusieurs valeurs dans un seul objet facile à manipuler.


Structure générale

static (<Type1>, <Type2>, ...) NomMethode(<paramètres>)
{
    // traitement
    return (valeur1, valeur2, ...);
}

Exemple simple

static (int somme, int produit) Calculer(int a, int b)
{
    int s = a + b;
    int p = a * b;
    return (s, p);
}

Utilisation :

var resultats = Calculer(3, 5);
Console.WriteLine($"Somme : {resultats.somme}, Produit : {resultats.produit}");
// Somme : 8, Produit : 15

🧠 Explication

Le type de retour ici est un tuple (int, int), c’est-à-dire une valeur composée de deux éléments.

➡️ Cela permet de regrouper plusieurs résultats dans une seule structure, sans créer de classe ni utiliser out.


🔍 Détail du fonctionnement

static (int somme, int produit) Calculer(int a, int b)
{
    int s = a + b;
    int p = a * b;
    return (s, p);
}
  • (int somme, int produit) → indique que la méthode renvoie deux entiers
  • return (s, p); → crée un tuple contenant deux valeurs
  • Les noms somme et produit permettent de donner un sens à chaque élément

Quand tu appelles la méthode :

var resultats = Calculer(3, 5);
Console.WriteLine(resultats.somme);   // 8
Console.WriteLine(resultats.produit); // 15

⚠️ Important : Item1 / Item2 et tuples nommés

Il existe deux familles de tuples en .NET :
- Tuple<...> (classe, .NET 4.x) — accès via Item1, Item2, …
- ValueTuple<...> (type valeur, C# 7+) — accès via noms (ex. somme, produit) et via Item1, Item2, …

Avec les tuples nommés en C# 7+, les deux accès fonctionnent :

var r = Calculer(3, 5);
Console.WriteLine(r.somme);  // ✅ 8
Console.WriteLine(r.produit);// ✅ 15
Console.WriteLine(r.Item1);  // ✅ 8 (nom par défaut toujours disponible)
Console.WriteLine(r.Item2);  // ✅ 15

✅ Les noms par défaut Item1, Item2, etc. restent utilisables même si vous avez donné des noms explicites aux éléments.
💡 Cependant, certains IDE peuvent privilégier l’auto-complétion sur les noms explicites pour la lisibilité.

Si tu n’attribues pas de noms :

static (int, int) Calculer(int a, int b) => (a + b, a * b);

var r = Calculer(3, 5);
Console.WriteLine(r.Item1); // ✅ 8
Console.WriteLine(r.Item2); // ✅ 15

Déclaration Accès possible Recommandé
(int somme, int produit) r.somme, r.produit, r.Item1, r.Item2 ✅ Utiliser les noms pour la clarté
(int, int) r.Item1, r.Item2 ⚠️ OK mais moins expressif
Tuple<int,int> Item1, Item2 (classe, plus lourde) 🚫 À éviter pour du code moderne

✨ Autre exemple : une méthode qui retourne des statistiques

Voici un exemple plus concret : une méthode qui retourne la moyenne et la note la plus haute d’un tableau d’étudiants 🎓

static (double moyenne, int max) AnalyserNotes(int[] notes)
{
    double moyenne = notes.Average();
    int max = notes.Max();
    return (moyenne, max);
}

Utilisation :

var resultats = AnalyserNotes(new int[] { 10, 14, 18, 7, 12 });
Console.WriteLine($"Moyenne : {resultats.moyenne}, Meilleure note : {resultats.max}");

📤 Résultat :

Moyenne : 12.2, Meilleure note : 18


🧩 À retenir

Accès Exemple Résultat
Par nom resultats.moyenne 12.2
Par position (si noms absents) resultats.Item1 12.2
Tuple complet (12.2, 18) Affiche les deux valeurs ensemble

💬 Les tuples rendent ton code plus clair quand une méthode doit renvoyer plusieurs informations liées.


Déstructuration d’un tuple

Tu peux décomposer le tuple directement à la réception :

(int somme, int produit) = Calculer(4, 6);
Console.WriteLine($"Somme : {somme}, Produit : {produit}");

💡 Très pratique pour éviter d’avoir à manipuler un objet intermédiaire.


Exemple complet

static (int min, int max) TrouverBornes(int[] tableau)
{
    int min = tableau.Min();
    int max = tableau.Max();
    return (min, max);
}

static void Main()
{
    int[] nombres = { 5, 2, 9, 1, 7 };
    var (min, max) = TrouverBornes(nombres);
    Console.WriteLine($"Minimum : {min}, Maximum : {max}");
}

📤 Résultat :

Minimum : 1, Maximum : 9


💡 Bonnes pratiques : var vs type explicite

"Entre simplicité et clarté, le bon code choisit… les deux."

Un développeur pragmatique

var : pratique et moderne

var permet de laisser le compilateur déduire automatiquement le type d’une variable à partir de la valeur qui lui est assignée.

var resultat = Calculer(3, 5);
Console.WriteLine(resultat.somme);

✅ Avantages :

  • Code plus court et lisible
  • Moins de répétition de types
  • Idéal quand le type est évident dans le contexte

⚠️ Attention :

  • Le type est quand même déterminé à la compilationvar n’est pas dynamique
  • Si le type n’est pas clair au premier regard, le code devient moins lisible

On peut aussi afficher le type complet pour plus de compréhension :

(int somme, int produit) resultat = Calculer(3, 5);
Console.WriteLine(resultat.produit);

✅ Avantages :

  • Code plus explicite (on sait exactement ce que la méthode retourne)
  • Plus facile pour les débutants
  • Recommandé dans le cadre d’un cours ou d’une relecture de code

Recommandation pédagogique

  1. Commencer avec le type explicite → comprendre ce que la méthode retourne.
  2. Introduire ensuite var → montrer qu’il simplifie le code sans changer le comportement.

💬 "Le bon code est celui qu’on comprend, même sans le compilateur."


🧩 Quiz – var ou pas var ?

Testez vos connaissances ! 📝 Clique pour découvrir la réponse.

1️⃣ Que fait vraiment le mot-clé var ?
A. Crée un type dynamique
B. Laisse le compilateur deviner le type
C. Rend la variable globale
D. Supprime le typage
E. Change le type à l’exécution
✅ Afficher la réponse
Réponse B : var laisse le compilateur inférer le type à la compilation.

2️⃣ Dans quel cas éviter var ?
A. Quand le type est évident
B. Quand le type est complexe ou peu clair
C. Toujours
D. Jamais
E. Quand on utilise un tuple
✅ Afficher la réponse
Réponse B : Évite var quand le type n’est pas évident, pour garder un code clair.

3️⃣ Quelle est la différence entre var resultat = Calculer(3, 5); et (int somme, int produit) resultat = Calculer(3, 5); ?
A. var crée un type différent
B. var est plus lent
C. Aucune : le type est le même
D. La deuxième ligne crée une liste
E. var utilise le mot-clé dynamic
✅ Afficher la réponse
Réponse C : Le type est identique dans les deux cas — (int, int).


⚠️ Attention

  • Les tuples ne remplacent pas les classes : ils sont utiles pour des retours temporaires
  • Les noms des champs dans un tuple sont optionnels mais fortement recommandés
  • Les tuples peuvent être imbriqués ((int, (string, bool))) mais deviennent vite illisibles
  • Avant C# 7, il fallait utiliser out ou créer une classe/structure pour renvoyer plusieurs valeurs

Comparaison rapide

Approche Avantages Inconvénients
out Compatible avec toutes les versions de C# Syntaxe plus lourde, nécessite déclaration préalable
Classe / struct Lisible, extensible Nécessite une définition externe
Tuple (C# 7+) Rapide, simple, lisible Moins adapté si le résultat doit être conservé longtemps

Quiz

Testez vos connaissances ! 📝 Clique sur chaque question pour découvrir la réponse.

1️⃣ Que permet le tuple dans une méthode ?
A. D’envoyer des emails
B. De retourner plusieurs valeurs
C. D’exécuter plusieurs méthodes
D. De fusionner des boucles
E. D’éviter le mot-clé return
✅ Afficher la réponse
Réponse B: Le tuple permet de retourner plusieurs valeurs dans une même méthode.

2️⃣ Quelle est la bonne déclaration ?
A. static tuple(int, int) Methode()
B. static (int, int) Methode()
C. static Tuple Methode()
D. static tuple<int, int> Methode()
E. static void Methode(int, int)
✅ Afficher la réponse
Réponse B: La syntaxe correcte est (int, int) sans mot-clé tuple.

3️⃣ Comment accéder à la deuxième valeur d’un tuple nommé ?
A. resultat.2
B. resultat.Item2
C. resultat[1]
D. resultat.produit
E. resultat.valeur2
✅ Afficher la réponse
Réponse D: On accède à la valeur via son nom (resultat.produit).

4️⃣ Quelle est la différence entre Tuple<int, int> et (int, int) ?
A. Aucune
B. Le premier est une classe, le second est une nouvelle syntaxe simplifiée (C# 7+)
C. Le premier est plus rapide
D. Le second ne fonctionne qu’avec ref
E. Le premier est réservé à LINQ
✅ Afficher la réponse
Réponse B: Tuple<int, int> crée un objet de classe, alors que (int, int) est un type valeur plus léger et moderne.

5️⃣ Quelle syntaxe déstructure le tuple ?
A. (a, b) = Methode();
B. tuple = Methode(a, b);
C. int a = tuple(0);
D. return (a, b);
E. tuple[a, b] = Methode();
✅ Afficher la réponse
Réponse A: On peut déstructurer un tuple directement avec (a, b) = Methode();.


Navigation

Introduction Sans paramètre Avec paramètre Avec retour Par référence / Out Retour multiple (out) Retour multiple (tuples) Travail pratique


Pour aller plus loin