173 votes

Qu'est-ce qui est le mieux, la valeur de retour ou le paramètre de sortie ?

Si nous voulons obtenir une valeur à partir d'une méthode, nous pouvons utiliser l'une ou l'autre des valeurs de retour, comme ceci :

public int GetValue(); 

ou :

public void GetValue(out int x);

Je ne comprends pas vraiment les différences entre eux, et donc, je ne sais pas lequel est le meilleur. Pouvez-vous m'expliquer cela ?

Merci.

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.

166voto

Jon Skeet Points 692016

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;

2 votes

Vous m'avez fait croire que la valeur de retour est bien meilleure :). Mais je me demande toujours ce qui se passe "en profondeur". Je veux dire, la valeur de retour et le paramètre de sortie, sont-ils différents dans la façon dont ils sont créés, assignés et retournés ?

2 votes

TryParse est le meilleur exemple de cas où l'utilisation d'un paramètre de sortie est appropriée et propre. Bien que je l'aie utilisé dans des cas particuliers comme if (WorkSucceeded(out List<string> errors) qui est fondamentalement le même modèle que TryParse.

0 votes

TryParse pour les types de valeurs peut également être représenté en utilisant des types de valeurs nullables. Parfois, c'est plus propre, parfois non.

30voto

sharpcloud Points 4141

Ce qui est mieux dépend de votre situation particulière. Un des raisons out existe pour faciliter le renvoi de plusieurs valeurs à partir d'un appel de méthode :

public int ReturnMultiple(int input, out int output1, out int output2)
{
    output1 = input + 1;
    output2 = input + 2;

    return input;
}

L'un n'est donc pas par définition meilleur que l'autre. Mais en général, il est préférable d'utiliser un rendement simple, sauf si vous êtes dans la situation décrite ci-dessus.

EDIT : Il s'agit d'un échantillon démontrant l'une des raisons pour lesquelles le mot-clé existe. Ce qui précède ne doit en aucun cas être considéré comme une meilleure pratique.

2 votes

Je ne suis pas d'accord avec ça, pourquoi ne pas retourner une structure de données avec 4 ints ? C'est vraiment déroutant.

1 votes

Il est évident qu'il existe d'autres (et de meilleures) façons de renvoyer des valeurs multiples, je ne fais que donner au PO une raison de l'existence de out en premier lieu.

3 votes

Je suis d'accord avec @Cloud. Ce n'est pas parce que ce n'est pas le meilleur moyen qu'il ne devrait pas exister.

26voto

Martin Peck Points 8078

Vous devriez généralement préférer une valeur de retour à un paramètre de sortie. Les paramètres out sont un mal nécessaire si vous vous retrouvez à écrire du code qui doit faire deux choses. Un bon exemple de ceci est le modèle Try (tel que Int32.TryParse).

Considérons ce que l'appelant de vos deux méthodes devrait faire. Pour le premier exemple, je peux écrire ceci...

int foo = GetValue();

Remarquez que je peux déclarer une variable et l'assigner via votre méthode en une seule ligne. Pour le 2ème exemple, cela ressemble à ceci...

int foo;
GetValue(out foo);

Je suis maintenant obligé de déclarer ma variable au début et d'écrire mon code sur deux lignes.

mise à jour

Les directives de conception de la structure .NET constituent un bon point de départ pour ce type de questions. Si vous avez la version papier, vous pouvez voir les annotations d'Anders Hejlsberg et d'autres sur ce sujet (page 184-185), mais la version en ligne est ici...

http://msdn.microsoft.com/en-us/library/ms182131(VS.80).aspx

Si vous avez besoin de renvoyer deux éléments à partir d'une API, il est préférable de les regrouper dans une structure/classe plutôt que dans un paramètre out.

0 votes

Excellente réponse, en particulier la référence à TryParse, une fonction (commune) qui oblige les développeurs à utiliser les variables out (peu communes).

8voto

Scott Cowan Points 1564

C'est la préférence principalement

Je préfère les retours et si vous avez plusieurs retours, vous pouvez les regrouper dans un DTO de résultat.

public class Result{
  public Person Person {get;set;}
  public int Sum {get;set;}
}

6voto

Brian Points 82719

Vous devriez presque toujours utiliser une valeur de retour. ' out Les paramètres ' créent un peu de friction pour beaucoup d'API, de compositionnalité, etc.

L'exception la plus notable qui me vient à l'esprit est lorsque vous souhaitez renvoyer plusieurs valeurs (.Net Framework ne dispose pas de tuples avant la version 4.0), comme avec la fonction TryParse modèle.

0 votes

Je ne sais pas si c'est une bonne pratique, mais Arraylist peut également être utilisé pour renvoyer plusieurs valeurs.

0 votes

@BA non ce n'est pas une bonne pratique, les autres utilisateurs ne sauraient pas ce que contient cette Arraylist, ni à quelle position ils se trouvent. Par exemple, je veux retourner la quantité d'octets lus et aussi la valeur. out ou des tuples qui sont nommés seraient beaucoup mieux. ArrayList, ou toute autre liste, ne serait utile que si vous voulez renvoyer une collection de choses, par exemple une liste de personnes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X