J'ai lu la version C ++ de cette question mais je ne l'ai pas vraiment comprise.
Quelqu'un peut-il expliquer clairement si cela peut être fait et comment?
J'ai lu la version C ++ de cette question mais je ne l'ai pas vraiment comprise.
Quelqu'un peut-il expliquer clairement si cela peut être fait et comment?
Réponses:
En C # 7 et supérieur, voir cette réponse .
Dans les versions précédentes, vous pouvez utiliser le tuple de .NET 4.0 + :
Par exemple:
public Tuple<int, int> GetMultipleValue()
{
return Tuple.Create(1,2);
}
Les tuples avec deux valeurs ont Item1
et Item2
comme propriétés.
public (int sum, int count) GetMultipleValues() { return (1, 2); }
Cet exemple est tiré de notre exemple de rubrique Documentation à ce sujet .
Maintenant que C # 7 est sorti, vous pouvez utiliser la nouvelle syntaxe Tuples incluse
(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 ensuite ê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 aux 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 une jolie nouvelle fonctionnalité:
(string first, string middle, string last) = LookupName(id1); // deconstructing declaration
Consultez ce lien pour voir plus d'exemples sur ce qui peut être fait :)
Vous pouvez utiliser trois façons différentes
1. paramètres ref / out
en utilisant ref:
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;
}
en utilisant:
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. struct / classe
en utilisant struct:
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;
}
en 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 de 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;
}
Tuples C # 7
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 faire cela en C #. Ce que vous pouvez faire, c'est avoir un out
paramètre ou retourner votre propre classe (ou struct si vous voulez qu'il soit immuable).
public int GetDay(DateTime date, out string name)
{
// ...
}
Utilisation d'une classe (ou d'une structure) personnalisée
public DayOfWeek GetDay(DateTime date)
{
// ...
}
public class DayOfWeek
{
public int Day { get; set; }
public string Name { get; set; }
}
async
méthodes. Tuple
est la voie à suivre. (J'utilise cependant des out
paramètres dans des opérations synchrones; ils sont en effet utiles dans ces cas.)
Si vous voulez renvoyer plusieurs valeurs, vous pouvez soit renvoyer une classe / structure contenant les valeurs que vous souhaitez renvoyer, soit 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
}
L'affiche précédente a raison. Vous ne pouvez pas renvoyer plusieurs valeurs à partir d'une méthode C #. Cependant, vous avez deux options:
Les avantages et les inconvénients ici sont souvent difficiles à comprendre. Si vous retournez une structure, assurez-vous qu'elle est petite car les structures sont de type valeur et passées sur la pile. Si vous retournez une instance d'une classe, vous pouvez utiliser ici certains modèles de conception pour éviter de causer des problèmes - les membres des classes peuvent être modifiés car C # transmet les objets par référence (vous n'avez pas ByVal comme vous le faisiez dans VB ).
Enfin, vous pouvez utiliser des paramètres de sortie, mais je limiterais l'utilisation de cela aux scénarios lorsque vous n'avez que quelques paramètres (comme 3 ou moins) - sinon les choses deviennent laides et difficiles à maintenir. De plus, l'utilisation des paramètres de sortie peut être un frein à l'agilité car la signature de votre méthode devra changer chaque fois que vous aurez besoin d'ajouter quelque chose à la valeur de retour tandis qu'en retournant une structure ou une instance de classe, vous pouvez ajouter des membres sans modifier la signature de la méthode.
D'un point de vue architectural, je déconseille d'utiliser des paires clé-valeur ou des 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 quelles seront les clés et ce que signifient les valeurs et si le développeur travaillant sur l'implémentation interne modifie la façon dont le dictionnaire ou KVP est créé, il pourrait facilement créer une cascade d'échecs dans toute l'application.
Exception
si la deuxième valeur que vous souhaitez renvoyer est disjonctive par rapport à la première: comme lorsque vous souhaitez renvoyer soit une sorte de valeur réussie, soit une sorte de valeur non réussie.
Vous renvoyez une instance de classe ou utilisez des paramètres. Voici un exemple de paramètres:
void mymethod(out int param1, out int param2)
{
param1 = 10;
param2 = 20;
}
Appelez ça comme ceci:
int i, j;
mymethod(out i, out j);
// i will be 20 and j will be 10
Il y a plusieurs façons; mais si vous ne voulez pas créer un nouvel objet ou structure ou quelque chose comme ça, vous pouvez faire comme ci-dessous après C # 7.0 :
(string firstName, string lastName) GetName(string myParameter)
{
var firstName = myParameter;
var lastName = myParameter + " something";
return (firstName, lastName);
}
void DoSomethingWithNames()
{
var (firstName, lastName) = GetName("myname");
}
En C # 7 Il y a une nouvelle Tuple
syntaxe:
static (string foo, int bar) GetTuple()
{
return ("hello", 5);
}
Vous pouvez renvoyer cela sous forme d'enregistrement:
var result = GetTuple();
var foo = result.foo
// foo == "hello"
Vous pouvez également utiliser la nouvelle syntaxe du 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 Tuple<string, int>
( selon la réponse acceptée ) avec Item1
et Item2
au lieu de foo
et bar
. Cela signifie que la sérialisation (ou la désérialisation) utilisera ces noms de propriété à la place.
Donc, pour la sérialisation, déclarez une classe d'enregistrement et renvoyez-la à la place.
Une autre nouveauté de C # 7 est une syntaxe améliorée pour les out
paramètres. Vous pouvez désormais déclarer l' out
inline, ce qui est mieux adapté dans certains contextes:
if(int.TryParse("123", out int result)) {
// Do something with result
}
Cependant, vous l'utiliserez principalement dans les propres bibliothèques de .NET, plutôt que dans vos propres fonctions.
Certaines réponses suggèrent d'utiliser des paramètres, mais je recommande de ne pas l'utiliser car ils ne fonctionnent pas avec les méthodes asynchrones . Voir ceci pour plus d'informations.
D'autres réponses ont indiqué l'utilisation de Tuple, que je recommanderais également, 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}.");
De plus amples informations peuvent être trouvées ici .
Il y a plusieurs moyens de le faire. Vous pouvez utiliser des ref
paramètres:
int Foo(ref Bar bar) { }
Cela transmet une référence à la fonction permettant ainsi à la fonction de modifier l'objet dans la pile du code appelant. Bien qu'il ne s'agisse pas techniquement d'une valeur "renvoyée", c'est un moyen pour qu'une fonction fasse quelque chose de similaire. Dans le code ci-dessus, la fonction retournerait un int
et (potentiellement) modifierbar
.
Une autre approche similaire consiste à utiliser un out
paramètre. Un out
paramètre est identique à un ref
paramètre avec une règle supplémentaire appliqué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 de revenir. Outre cette règle, un out
paramètre fonctionne comme unref
paramètre.
L'approche finale (et la meilleure dans la plupart des cas) consiste à créer un type qui encapsule les deux valeurs et permet à la fonction de renvoyer:
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.
Non, vous ne pouvez pas renvoyer 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 existe quelques alternatives:
Vous pouvez renvoyer un tableau d'objet type avec les multiples valeurs que vous souhaitez.
private object[] DoSomething()
{
return new [] { 'value1', 'value2', 3 };
}
Vous pouvez utiliser des out
paramètres.
private string DoSomething(out string outparam1, out int outparam2)
{
outparam1 = 'value2';
outparam2 = 3;
return 'value1';
}
En C # 4, vous pourrez utiliser le support intégré pour les tuples pour gérer cela facilement.
En attendant, il y a deux options.
Tout d'abord, vous pouvez utiliser des paramètres ref ou out pour affecter des valeurs à vos paramètres, qui sont retransmises à la routine d'appel.
Cela ressemble à ceci:
void myFunction(ref int setMe, out int youMustSetMe);
Deuxièmement, vous pouvez encapsuler vos valeurs de retour dans une structure ou une classe et les transmettre en tant que membres de cette structure. KeyValuePair fonctionne bien pour 2 - pour plus de 2, vous auriez besoin d'une classe ou d'une structure personnalisée.
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);
Production :
Sortie: 1, 2
Les classes, structures, collections et tableaux peuvent contenir plusieurs valeurs. Les paramètres de sortie et de référence peuvent également être définis dans une fonction. Le retour de plusieurs valeurs est possible dans les langages dynamiques et fonctionnels au moyen de tuples, mais pas en C #.
Il existe principalement deux méthodes. 1. Utilisez les paramètres out / ref 2. Retournez un tableau d'objets
Voici les Two
méthodes de base :
1) Utilisation de ' out
' comme paramètre
Vous pouvez également utiliser 'out' pour les versions 4.0 et mineures.
Exemple de «sortie»:
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();
}
}
}
Production:
L'aire du rectangle est de 20
Le périmètre du rectangle est de 18
* Remarque: * 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 appelante accède au paramètre modifié.
2) Tuple<T>
Exemple de tuple:
Renvoyer plusieurs valeurs DataType à l'aide de 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);
}
}
}
Production
perl
java
c#
1
2
3
REMARQUE: l' utilisation de Tuple est valide à partir de Framework 4.0 et supérieur . Tuple
le type est a class
. Il sera alloué dans un emplacement distinct sur le tas géré en mémoire. Une fois que vous avez créé le Tuple
, vous ne pouvez pas modifier ses valeurs fields
. Cela fait Tuple
plus comme un struct
.
Une méthode prenant un délégué peut fournir plusieurs valeurs à l'appelant. Cela emprunte à ma réponse ici et utilise un peu la réponse acceptée par Hadas .
delegate void ValuesDelegate(int upVotes, int comments);
void GetMultipleValues(ValuesDelegate callback)
{
callback(1, 2);
}
Les appelants fournissent un lambda (ou une fonction nommée) et intellisense aide en copiant les noms de variables du délégué.
GetMultipleValues((upVotes, comments) =>
{
Console.WriteLine($"This post has {upVotes} Up Votes and {comments} Comments.");
});
Utilisez simplement de la 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 fonction renvoie le quotient qui intéresse principalement la plupart des appelants. De plus, il stocke le reste en tant que membre de données, qui est facilement accessible par l'appelant par la suite.
De cette façon, vous pouvez avoir de nombreuses "valeurs de retour" supplémentaires, très utiles si vous implémentez des appels de base de données ou de réseau, où de nombreux messages d'erreur peuvent être nécessaires, mais uniquement en cas d'erreur.
J'ai également introduit cette solution dans la question C ++ à laquelle OP fait référence.
La future version de C # va inclure des tuples nommés. Jetez un œil à cette session channel9 pour la démo https://channel9.msdn.com/Events/Build/2016/B889
Passez à 13h00 pour les tuples. Cela permettra des trucs comme:
(int sum, int count) Tally(IEnumerable<int> list)
{
// calculate stuff here
return (0,0)
}
int resultsum = Tally(numbers).sum
(exemple incomplet de la vidéo)
Vous pouvez utiliser un objet dynamique. Je pense qu'il a une meilleure lisibilité 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) Tuple - 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) out (1,64 ns) ou ref 4) Créez votre propre classe / structure personnalisée
ns -> nanosecondes
Référence: multiple-return-values .
tu peux essayer ça
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
yield return "value1"; yield return "value2";
as pour ne pas avoir à créer explicitement un nouveau string[]
?
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;
}
Une réponse rapide spécialement pour les types de tableaux renvoie:
private int[] SumAndSub(int A, int B)
{
return new[] { A + B, A - B };
}
En utilisant:
var results = SumAndSub(20, 5);
int sum = results[0];
int sub = results[1];