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?
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.
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 :)
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);
}
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).
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; }
}
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
}
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.
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
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.
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.
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';
}
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.
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
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 .
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#.
il y a principalement deux méthodes. 1. Paramètres d'utilisation / ref 2. Retourner un tableau d'objets
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
.
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.");
});
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.
de cet" article 151920920", vous pouvez utiliser trois options comme les messages ci-dessus dit.
KeyValuePair est le chemin le plus rapide.
out est à la seconde.
Tuple est le plus lent.
de toute façon, cela dépend de ce qui est le mieux pour votre scénario.
, 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;
}
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 .
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)
vous pouvez essayer ceci
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
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;
}
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];