Comment puis-je retourner plusieurs valeurs d'une fonction en C#?

j'ai lu la version C++ de cette question mais je ne l'ai pas vraiment compris.

quelqu'un Peut-il expliquer clairement si cela peut être fait et comment?

306
demandé sur Community 2009-04-14 19:11:57

25 réponses

utiliser .NET 4.0+'s Tuple :

Par Exemple:

public Tuple<int, int> GetMultipleValue()
{
     return Tuple.Create(1,2);
}

Tuples avec deux valeurs ont Item1 et Item2 comme propriétés.

494
répondu Hadas 2017-12-16 19:17:21

maintenant que C# 7 est sorti, vous pouvez utiliser la nouvelle syntaxe Tuples

(string, string, string) LookupName(long id) // tuple return type
{
    ... // retrieve first, middle and last from data storage
    return (first, middle, last); // tuple literal
}

qui pourrait alors être utilisé comme ceci:

var names = LookupName(id);
WriteLine($"found {names.Item1} {names.Item3}.");

vous pouvez également fournir des noms à vos éléments (ils ne sont donc pas" Item1"," Item2", etc.). Vous pouvez le faire en ajoutant un nom à la signature ou les méthodes de retour:

(string first, string middle, string last) LookupName(long id) // tuple elements have names

ou

return (first: first, middle: middle, last: last); // named tuple elements in a literal

Ils peuvent également être déconstruits, ce qui est un jolie nouvelle caractéristique:

(string first, string middle, string last) = LookupName(id1); // deconstructing declaration

Check out ce lien pour voir plus d'exemples sur ce qui peut être fait :)

180
répondu Francisco Noriega 2018-08-03 21:36:18

vous pouvez utiliser trois façons différentes

1. paramètres de ref / out

utilisant réf:

static void Main(string[] args)
{
    int a = 10;
    int b = 20;
    int add = 0;
    int multiply = 0;
    Add_Multiply(a, b, ref add, ref multiply);
    Console.WriteLine(add);
    Console.WriteLine(multiply);
}

private static void Add_Multiply(int a, int b, ref int add, ref int multiply)
{
    add = a + b;
    multiply = a * b;
}

aide:

static void Main(string[] args)
{
    int a = 10;
    int b = 20;
    int add;
    int multiply;
    Add_Multiply(a, b, out add, out multiply);
    Console.WriteLine(add);
    Console.WriteLine(multiply);
}

private static void Add_Multiply(int a, int b, out int add, out int multiply)
{
    add = a + b;
    multiply = a * b;
}

2. structure / classe

utilisant la structure:

struct Result
{
    public int add;
    public int multiply;
}
static void Main(string[] args)
{
    int a = 10;
    int b = 20;
    var result = Add_Multiply(a, b);
    Console.WriteLine(result.add);
    Console.WriteLine(result.multiply);
}

private static Result Add_Multiply(int a, int b)
{
    var result = new Result
    {
        add = a * b,
        multiply = a + b
    };
    return result;
}

utilisant la classe:

class Result
{
    public int add;
    public int multiply;
}
static void Main(string[] args)
{
    int a = 10;
    int b = 20;
    var result = Add_Multiply(a, b);
    Console.WriteLine(result.add);
    Console.WriteLine(result.multiply);
}

private static Result Add_Multiply(int a, int b)
{
    var result = new Result
    {
        add = a * b,
        multiply = a + b
    };
    return result;
}

3. Tuple

Classe Tuple

static void Main(string[] args)
{
    int a = 10;
    int b = 20;
    var result = Add_Multiply(a, b);
    Console.WriteLine(result.Item1);
    Console.WriteLine(result.Item2);
}

private static Tuple<int, int> Add_Multiply(int a, int b)
{
    var tuple = new Tuple<int, int>(a + b, a * b);
    return tuple;
}

C# 7 Tuples

static void Main(string[] args)
{
    int a = 10;
    int b = 20;
    (int a_plus_b, int a_mult_b) = Add_Multiply(a, b);
    Console.WriteLine(a_plus_b);
    Console.WriteLine(a_mult_b);
}

private static (int a_plus_b, int a_mult_b) Add_Multiply(int a, int b)
{
    return(a + b, a * b);
}
115
répondu Devrim Altınkurt 2017-12-29 18:57:48

Vous ne pouvez pas le faire en C#. Ce que vous pouvez faire est d'avoir un paramètre out ou retourner votre propre classe (ou struct si vous voulez qu'elle soit immuable).

Utilisation du paramètre out
public int GetDay(DateTime date, out string name)
{
  // ...
}
Utiliser la classe personnalisée (ou struct)
public DayOfWeek GetDay(DateTime date)
{
  // ...
}

public class DayOfWeek
{
  public int Day { get; set; }
  public string Name { get; set; }
}
74
répondu Samuel 2009-04-14 15:46:51

si vous voulez dire retourner plusieurs valeurs, vous pouvez soit retourner une classe / struct contenant les valeurs que vous voulez retourner, ou utiliser le mot-clé" out "sur vos paramètres, comme ceci:

public void Foo(int input, out int output1, out string output2, out string errors) {
    // set out parameters inside function
}
37
répondu Chris Doggett 2009-04-14 15:15:01

affiche précédente à droite. Vous ne pouvez pas retourner plusieurs valeurs d'une méthode C#. Cependant, vous avez quelques options:

  • retourner une structure qui contient plusieurs membres
  • Retourner une instance d'une classe
  • utiliser les paramètres de sortie (en utilisant les mots-clés out ou ref )
  • Utiliser un dictionnaire ou une paire clé-valeur en sortie

le pour et le contre ici sont souvent difficiles à comprendre. Si vous retournez une structure, assurez-vous qu'elle est petite parce que les structures sont de type valeur et transmises sur la pile. Si vous renvoyez une instance d'une classe, il y a ici quelques motifs que vous pourriez vouloir utiliser pour éviter de causer des problèmes - les membres des classes peuvent être modifiés parce que C# passe des objets par référence (vous n'avez pas ByVal comme vous l'avez fait dans VB).

Enfin, vous pouvez utiliser les paramètres de sortie, mais Je limite l'utilisation de cette scénarios lorsque vous avez seulement un couple (comme 3 ou moins) de paramètres - sinon, les choses se corsent et difficiles à maintenir. En outre, l'utilisation des paramètres de sortie peut être un inhibiteur à l'agilité parce que votre signature de méthode devra changer chaque fois que vous avez besoin d'ajouter quelque chose à la valeur de retour tandis que retourner une instance de struct ou de classe vous pouvez ajouter des membres sans modifier la signature de méthode.

d'un point de vue architectural je voudrais déconseiller l'utilisation de paires de valeurs clés ou de dictionnaires. Je trouve que ce style de codage nécessite des "connaissances secrètes" dans le code qui consomme la méthode. Il doit savoir à l'avance ce que les clés vont être et ce que les valeurs signifient et si le développeur travaillant sur l'implémentation interne change la façon dont le dictionnaire ou KVP est créé, il pourrait facilement créer une cascade d'échecs dans toute l'application.

33
répondu Kevin Hoffman 2009-04-14 15:18:02

vous retournez une instance de classe ou utilisez out paramètres. Voici un exemple de paramètres:

void mymethod(out int param1, out int param2)
{
    param1 = 10;
    param2 = 20;
}

appelez ça comme ça:

int i, j;
mymethod(out i, out j);
// i will be 20 and j will be 10
18
répondu Keltex 2018-06-20 13:42:29

Il y a plusieurs façons de le faire. Vous pouvez utiliser les paramètres ref :

int Foo(ref Bar bar) { }

passe une référence à la fonction permettant ainsi à la fonction de modifier l'objet dans la pile du code appelant. Bien que ce ne soit pas techniquement une valeur "retournée", c'est une façon de faire faire quelque chose de similaire à une fonction. Dans le code ci-dessus, la fonction retournerait un int et (potentiellement) modifierait bar .

un autre une approche similaire consiste à utiliser un paramètre out . Un paramètre out est identique à un paramètre ref avec une règle supplémentaire imposée par le compilateur. Cette règle est que si vous passez un out paramètre dans une fonction, cette fonction est nécessaire pour définir sa valeur avant le retour. En plus de cette règle, un paramètre out fonctionne comme un paramètre ref .

l'approche finale (et la meilleure dans la plupart des cas) est de créer un type qui encapsule les deux valeurs et permet à la fonction de retourner que:

class FooBar 
{
    public int i { get; set; }
    public Bar b { get; set; }
}

FooBar Foo(Bar bar) { }

cette approche finale est plus simple et plus facile à lire et à comprendre.

11
répondu Andrew Hare 2009-04-14 15:19:55

dans C# 4, vous serez en mesure d'utiliser le support intégré pour tuples pour gérer cela facilement.

en attendant, il y a deux options.

tout d'abord, vous pouvez utiliser les paramètres ref ou out pour assigner des valeurs à vos paramètres, qui sont passés à la routine d'appel.

on dirait:

void myFunction(ref int setMe, out int youMustSetMe);

Deuxièmement, vous pouvez envelopper vos valeurs de retour dans une structure ou une classe, et les passer en arrière comme les membres de cette structure. KeyValuePair fonctionne bien pour 2 - pour plus de 2, vous auriez besoin d'une classe personnalisée ou d'une structure.

10
répondu Reed Copsey 2009-04-14 15:17:27

Non, vous ne pouvez pas retourner plusieurs valeurs d'une fonction en C# (pour les versions inférieures à C# 7), du moins pas de la façon dont vous pouvez le faire en Python.

cependant, il y a quelques alternatives:

vous pouvez retourner un tableau d'objet de type avec les valeurs multiples que vous voulez dedans.

private object[] DoSomething()
{
    return new [] { 'value1', 'value2', 3 };
}

vous pouvez utiliser les paramètres out .

private string DoSomething(out string outparam1, out int outparam2)
{
    outparam1 = 'value2';
    outparam2 = 3;
    return 'value1';
}
10
répondu dustyburwell 2017-03-14 00:11:13

dans C#7 Il y a une nouvelle syntaxe Tuple :

static (string foo, int bar) GetTuple()
{
    return ("hello", 5);
}

vous pouvez retourner ceci comme un enregistrement:

var result = GetTuple();
var foo = result.foo
// foo == "hello"

vous pouvez également utiliser la nouvelle syntaxe de déconstructeur:

(string foo) = GetTuple();
// foo == "hello"

soyez prudent avec la sérialisation cependant, tout cela est du sucre syntaxique - dans le code compilé réel ce sera un Tupel<string, int> (comme selon la réponse acceptée ) avec Item1 et Item2 à la place de foo et bar . Cela signifie que serialisation (ou deserialisation) utilisera ces noms de propriétés à la place.

ainsi, pour la sérialisation déclarer une classe d'enregistrement et retourner cela à la place.

aussi nouveau en C#7 est une syntaxe améliorée pour les paramètres out . Vous pouvez maintenant déclarer le out en ligne, qui est mieux adapté dans certains contextes:

if(int.TryParse("123", out int result)) {
    // Do something with result
}

cependant, la plupart du temps, vous allez utiliser ceci dans. propres bibliothèques, plutôt que dans ses propres fonctions.

8
répondu Keith 2017-05-23 12:10:41

vous pouvez essayer ce "KeyValuePair"

private KeyValuePair<int, int> GetNumbers()
{
  return new KeyValuePair<int, int>(1, 2);
}


var numbers = GetNumbers();

Console.WriteLine("Output : {0}, {1}",numbers.Key, numbers.Value);

sortie:

sortie: 1, 2

6
répondu Rikin Patel 2012-03-06 10:53:42

certaines de ces réponses indiquent que l'utilisation paramètre de sortie mais je recommande ne pas utiliser cela en raison de ils ne fonctionnent pas avec les méthodes async . Voir ce pour plus d'informations.

autres réponses fournies à L'aide de Tuple, ce que je recommanderais aussi, mais en utilisant la nouvelle fonctionnalité introduite dans C# 7.0.

(string, string, string) LookupName(long id) // tuple return type
{
    ... // retrieve first, middle and last from data storage
    return (first, middle, last); // tuple literal
}

var names = LookupName(id);
WriteLine($"found {names.Item1} {names.Item3}.");

pour plus d'informations, veuillez consulter ici .

6
répondu Luis Teijon 2017-05-23 12:26:37

les Classes, les Structures, les Collections et les tableaux peuvent contenir des valeurs multiples. Les paramètres de sortie et de référence peuvent également être définis dans une fonction. Return multiple values est possible dans les langages dynamiques et fonctionnels au moyen de tuples, mais pas en C#.

4
répondu Jose Basilio 2009-04-14 15:16:56

il y a principalement deux méthodes. 1. Paramètres d'utilisation / ref 2. Retourner un tableau d'objets

4
répondu blitzkriegz 2009-04-14 15:51:39

Voici les méthodes de base Two :

1) utilisation de out "comme paramètre Vous pouvez également utiliser " out " pour les versions 4.0 et mineures.

exemple de "out":

using System;

namespace out_parameter
{
  class Program
   {
     //Accept two input parameter and returns two out value
     public static void rect(int len, int width, out int area, out int perimeter)
      {
        area = len * width;
        perimeter = 2 * (len + width);
      }
     static void Main(string[] args)
      {
        int area, perimeter;
        // passing two parameter and getting two returning value
        Program.rect(5, 4, out area, out perimeter);
        Console.WriteLine("Area of Rectangle is {0}\t",area);
        Console.WriteLine("Perimeter of Rectangle is {0}\t", perimeter);
        Console.ReadLine();
      }
   }
}

sortie:

surface du Rectangle est de 20

périmètre du Rectangle est 18

* Note: *le out - mot-clé décrit les paramètres dont les emplacements variables réels sont copiés sur la pile de la méthode appelée, où ces mêmes emplacements peuvent être réécrits. Cela signifie que la méthode d'appel accédera au paramètre modifié.

2) Tuple<T>

exemple de Tuple:

Renvoi De Plusieurs Type De Données valeurs utilisant Tuple<T>

using System;

class Program
{
    static void Main()
    {
    // Create four-item tuple; use var implicit type.
    var tuple = new Tuple<string, string[], int, int[]>("perl",
        new string[] { "java", "c#" },
        1,
        new int[] { 2, 3 });
    // Pass tuple as argument.
    M(tuple);
    }

    static void M(Tuple<string, string[], int, int[]> tuple)
    {
    // Evaluate the tuple's items.
    Console.WriteLine(tuple.Item1);
    foreach (string value in tuple.Item2)
    {
        Console.WriteLine(value);
    }
    Console.WriteLine(tuple.Item3);
    foreach (int value in tuple.Item4)
    {
        Console.WriteLine(value);
    }
    }
}

Sortie

perl
java
c#
1
2
3

NOTE: L'utilisation de Tuple est valide à partir du cadre 4.0 et au-dessus de . Le type Tuple est un class . Il sera attribué dans un endroit séparé sur le tas géré en mémoire. Une fois que vous créez le Tuple , vous ne pouvez pas changer les valeurs de son fields . Cela rend le Tuple plus comme un struct .

4
répondu SHEKHAR SHETE 2013-12-26 06:23:21

une méthode prenant un délégué peut fournir des valeurs multiples à l'appelant. Ceci emprunte de ma réponse ici et utilise un peu de Hadas la réponse acceptée .

delegate void ValuesDelegate(int upVotes, int comments);
void GetMultipleValues(ValuesDelegate callback)
{
    callback(1, 2);
}
Les appelants

fournissent une lambda (ou une fonction nommée) et intellisense aide en copiant les noms variables du délégué.

GetMultipleValues((upVotes, comments) =>
{
     Console.WriteLine($"This post has {upVotes} Up Votes and {comments} Comments.");
});
3
répondu Scott Turner 2017-05-23 10:31:35

il suffit D'utiliser D'une manière OOP une classe comme celle-ci:

class div
{
    public int remainder;

    public int quotient(int dividend, int divisor)
    {
        remainder = ...;
        return ...;
    }
}

le membre de la fonction renvoie le quotient auquel la plupart des appelants sont principalement intéressés. En outre, il stocke le reste comme un membre de données, qui est facilement accessible par l'appelant après.

de cette façon, vous pouvez avoir beaucoup de "valeurs de retour" supplémentaires, très utile si vous implémentez des appels de base de données ou de réseau, où beaucoup de messages d'erreur peuvent être nécessaires, mais seulement dans le cas où un erreur se produit.

j'ai entré cette solution aussi dans la question C++ à laquelle OP fait référence.

2
répondu Roland 2014-11-21 10:32:39

, Vous pouvez utiliser un objet dynamique. Je pense qu'il est plus lisible que Tuple.

static void Main(string[] args){
    var obj = GetMultipleValues();
    Console.WriteLine(obj.Id);
    Console.WriteLine(obj.Name);
}

private static dynamic GetMultipleValues() {
    dynamic temp = new System.Dynamic.ExpandoObject();
    temp.Id = 123;
    temp.Name = "Lorem Ipsum";
    return temp;
}
2
répondu Ogge 2016-09-23 09:11:39

Façons de le faire:

1) KeyValuePair (meilleure Performance-0.32 ns):

    KeyValuePair<int, int> Location(int p_1, int p_2, int p_3, int p_4)
    {                 
         return new KeyValuePair<int,int>(p_2 - p_1, p_4-p_3);
    }

2) n-uplet - 5.40 ns:

    Tuple<int, int> Location(int p_1, int p_2, int p_3, int p_4)
    {
          return new Tuple<int, int>(p_2 - p_1, p_4-p_3);
    }

3) (1.64 ns) ou ref 4) Créer votre propre classe personnalisée / struct

ns - > nanosecondes

la Référence: plusieurs-retour-valeurs .

1
répondu Adham Sabry 2015-08-27 21:46:51

la future version de C# va inclure les tuples nommés. Regardez cette session channel9 pour la démo https://channel9.msdn.com/Events/Build/2016/B889

passer à 13h00 pour le truc de tuple. Cela permettra des choses comme:

(int sum, int count) Tally(IEnumerable<int> list)
{
// calculate stuff here
return (0,0)
}

int resultsum = Tally(numbers).sum

(exemple incomplet tiré de la vidéo)

1
répondu Niels 2016-06-28 08:23:24

vous pouvez essayer ceci

public IEnumerable<string> Get()
 {
     return new string[] { "value1", "value2" };
 }
0
répondu IMMORTAL 2013-08-16 09:38:55

vous pouvez également utiliser un OperationResult

public OperationResult DoesSomething(int number1, int number2)
{
// Your Code
var returnValue1 = "return Value 1";
var returnValue2 = "return Value 2";

var operationResult = new OperationResult(returnValue1, returnValue2);
return operationResult;
}
0
répondu Ruan 2016-09-13 12:21:02

Aujourd'hui, les programmeurs ont besoin de temps et de méthodes impardonnables. Une solution simple, efficace et rapide:

private int[] SumAndSub(int A, int B)
{
    return new[] { A + B , A - B };
}

L'utiliser quelque part;

int sum = SumAndSub(20, 5)[0];
int sub = SumAndSub(20, 5)[1];
0
répondu alienTech 2018-09-25 19:53:27