Les valeurs de retour sont presque toujours le bon choix lorsque la méthode n'a rien d'autre à retourner. (En fait, je ne vois pas de cas où j'aurais pu jamais voulez une méthode void avec un out
paramètre, si j'avais le choix. C# 7's Deconstruct
Les méthodes de déconstruction à l'aide de la langue constituent une exception très, très rare à cette règle).
En dehors de toute autre chose, cela évite à l'appelant de devoir déclarer la variable séparément :
int foo;
GetValue(out foo);
vs
int foo = GetValue();
Les valeurs de sortie empêchent également l'enchaînement de méthodes comme celle-ci :
Console.WriteLine(GetValue().ToString("g"));
(En fait, c'est aussi l'un des problèmes des setters de propriétés, et c'est pourquoi le modèle de construction utilise des méthodes qui renvoient le builder, par ex. myStringBuilder.Append(xxx).Append(yyy)
.)
De plus, les paramètres out sont légèrement plus difficiles à utiliser avec la réflexion et rendent généralement les tests plus difficiles également. (Plus d'efforts sont généralement déployés pour faciliter la simulation des valeurs de retour que des paramètres out). En fait, il n'y a rien que je puisse penser qui rende plus facile ...
Valeurs de retour FTW.
EDIT : En ce qui concerne ce qui se passe...
En fait, lorsque vous passez un argument pour un paramètre "out", vous ont pour passer dans une variable. (Les éléments d'un tableau sont également considérés comme des variables). La méthode que vous appelez n'a pas de "nouvelle" variable sur sa pile pour le paramètre - elle utilise votre variable pour le stockage. Toute modification de la variable est immédiatement visible. Voici un exemple qui montre la différence :
using System;
class Test
{
static int value;
static void ShowValue(string description)
{
Console.WriteLine(description + value);
}
static void Main()
{
Console.WriteLine("Return value test...");
value = 5;
value = ReturnValue();
ShowValue("Value after ReturnValue(): ");
value = 5;
Console.WriteLine("Out parameter test...");
OutParameter(out value);
ShowValue("Value after OutParameter(): ");
}
static int ReturnValue()
{
ShowValue("ReturnValue (pre): ");
int tmp = 10;
ShowValue("ReturnValue (post): ");
return tmp;
}
static void OutParameter(out int tmp)
{
ShowValue("OutParameter (pre): ");
tmp = 10;
ShowValue("OutParameter (post): ");
}
}
Résultats :
Return value test...
ReturnValue (pre): 5
ReturnValue (post): 5
Value after ReturnValue(): 10
Out parameter test...
OutParameter (pre): 5
OutParameter (post): 10
Value after OutParameter(): 10
La différence se situe à l'étape "post", c'est-à-dire après la modification de la variable locale ou du paramètre. Dans le test ReturnValue, cela ne fait aucune différence pour le test statique value
variable. Dans le test OutParameter, la variable value
est modifiée par la ligne tmp = 10;
4 votes
J'aimerais que le C# ait des valeurs de retour multiples comme Python, par exemple.
17 votes
@Trap Vous pouvez renvoyer un
Tuple
si vous le souhaitez, mais le consensus général est que si vous avez besoin de retourner plus d'une chose, les choses sont généralement liées d'une manière ou d'une autre et cette relation est généralement mieux exprimée comme une classe.2 votes
@Pharap Les tuples en C# dans leur forme actuelle sont tout simplement moches, mais ce n'est que mon opinion. D'autre part, le "consensus général" ne signifie rien du point de vue de l'utilisabilité et de la productivité. Vous ne créeriez pas une classe pour retourner un couple de valeurs pour la même raison que vous ne créeriez pas une classe pour retourner un couple de valeurs comme paramètre ref/out.
0 votes
@Trap
return Tuple.Create(x, y, z);
N'est-ce pas moche ? De plus, c'est un peu tard pour les introduire au niveau du langage. La raison pour laquelle je ne créerais pas une classe pour retourner des valeurs à partir d'un paramètre ref/out est que les paramètres ref/out n'ont vraiment de sens que pour les grandes structures mutables (comme les matrices) ou les valeurs optionnelles, et ce dernier point est discutable.0 votes
@Pharap L'équipe C# cherche activement à introduire les tuples au niveau du langage. Bien qu'il soit bienvenu la pléthore d'options dans .NET accablant maintenant - type anonyme, .NET
Tuple<>
et C# tuples . J'aurais juste souhaité que C# permette le retour de types anonymes à partir de méthodes dont le compilateur infère le type (commeauto
en Dlang).0 votes
@nawfal Je pense que je préférerais les tuples aux types anonymes. Le défaut avec cela est que cela signifierait que la signature de la méthode devrait inclure un moyen d'identifier le type anonyme. Il pourrait simplement retourner
object
mais cela serait plutôt inutile, et si la méthode était rendue publique, toute personne tentant de l'utiliser devrait savoir quels champs l'objet contient (ce qui serait gênant lorsqu'elle n'a pas accès au code source de la méthode).0 votes
@Pharap si l'équipe C# voulait ils pourraient déduire le type. Similaire à l'inférence de type dans le cas de
var x = new { };
C'est ce que Dlangauto
fait. La définition d'une méthode peut donc ressembler àpublic var Method() { }
. Vous avez de toute façon besoin d'un support au niveau du langage, qu'il s'agisse de tuples ou de types anonymes.0 votes
@nawfal Ce n'est pas le problème, le problème est l'exportation de la fonction ou son utilisation lorsque vous n'avez pas accès au code source du corps de la fonction. Comment identifier les membres d'une fonction
var
type ? Il faudrait probablement examiner une forme de métadonnées produites par le compilateur, ce qui n'est pas toujours pratique.0 votes
@Pharap quel problème voyez-vous dans l'exportation d'un type anonyme que l'exportation d'un type nommé n'a pas (ou même des tuples) ? Les types anonymes sont juste des types normaux mais sans nom (le compilateur leur donne le nom à la place du programmeur). Le langage True ne supporte pas actuellement les types anonymes en cross assembly mais c'est une question de support. Je ne vois pas de défi technique ou théorique.