web-dev-qa-db-fra.com

Quel est le meilleur, valeur de retour ou paramètre out?

Si nous voulons obtenir une valeur d'une méthode, nous pouvons utiliser l'une ou l'autre des valeurs renvoyées, 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 ce qui est le meilleur. Pouvez-vous m'expliquer cela?

Je vous remercie.

136
Vimvq1987

Les valeurs de retour sont presque toujours le bon choix lorsque la méthode n'a rien d'autre à renvoyer. (En fait, je ne peux imaginer de cas où je jamais voudrais une méthode vide avec un paramètre out, si j'avais le choix. Les méthodes Deconstruct de C # 7 pour la déconstruction prise en charge par le langage agissent très, très rare exception à cette règle.)

Mis à part tout le reste, cela évite à l'appelant de déclarer la variable séparément:

int foo;
GetValue(out foo);

contre

int foo = GetValue();

Les valeurs Out empêchent également le chaînage de méthodes comme ceci:

Console.WriteLine(GetValue().ToString("g"));

(En effet, c’est également l’un des problèmes rencontrés avec les régleurs de propriété et c’est pourquoi le modèle de générateur utilise des méthodes qui renvoient le générateur, par exemple myStringBuilder.Append(xxx).Append(yyy).)

De plus, les paramètres de sortie sont légèrement plus difficiles à utiliser avec la réflexion et rendent également les tests plus difficiles. (Il est généralement plus difficile de simuler les valeurs de retour que les paramètres de sortie). En gros, je ne peux penser à rien qui puisse rendre (facile} _...

Renvoie les valeurs FTW.

EDIT: En termes de ce qui se passe ...

Fondamentalement, lorsque vous passez un argument pour un paramètre "out", vous ayez à transmettre une variable. (Les éléments de tableau sont également classés en tant que variables.) La méthode que vous appelez ne contient pas de "nouvelle" variable pour le paramètre; elle utilise votre variable pour le stockage. Toute modification de la variable est immédiatement visible. Voici un exemple montrant 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 que la variable ou le paramètre local a été modifié. Dans le test ReturnValue, cela ne fait aucune différence avec la variable statique value. Dans le test OutParameter, la variable value est modifiée par la ligne tmp = 10;

147
Jon Skeet

Quoi de mieux, dépend de votre situation particulière. L'une des raisons pour lesquelles out existe consiste à faciliter le renvoi de plusieurs valeurs à partir d'un seul appel de méthode:

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

    return input;
}

Donc, l’un n’est pas, par définition, meilleur que l’autre. Mais généralement, vous voudriez utiliser un simple retour, à moins que vous n'ayez la situation ci-dessus par exemple.

EDIT: Voici un exemple 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 pratique exemplaire.

24
pyrocumulus

Vous devriez généralement préférer une valeur de retour à un paramètre out. Les paramètres sont un mal nécessaire si vous vous trouvez en train d'écrire du code qui doit faire 2 choses. Le modèle Try (par exemple, Int32.TryParse) en est un bon exemple.

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

int foo = GetValue();

Notez que je peux déclarer une variable et l’affecter via votre méthode sur une ligne. Pour le 2ème exemple cela ressemble à ceci ...

int foo;
GetValue(out foo);

Je suis maintenant obligé de déclarer ma variable à l'avance et d'écrire mon code sur deux lignes.

mettre à jour

Les directives de conception du .NET Framework constituent un bon point de départ pour poser ce type de question. Si vous avez la version du livre, 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 trouvez que vous devez renvoyer deux éléments d'une API, il serait préférable de les inclure dans une structure/classe.

23
Martin Peck

Il y a une raison d'utiliser un paramètre out qui n'a pas déjà été mentionnée: la méthode appelante est obligée de le recevoir. Si votre méthode produit une valeur que l'appelant ne doit pas ignorer, le fait de la remplacer par out force l'appelant à l'accepter spécifiquement:

 Method1();  // Return values can be discard quite easily, even accidentally

 int  resultCode;
 Method2(out resultCode);  // Out params are a little harder to ignore

Bien sûr, l'appelant peut toujours ignorer la valeur value dans un paramètre out, mais vous leur avez signalé son attention.

C'est un besoin rare. le plus souvent, vous devez utiliser une exception pour un problème réel ou renvoyer un objet avec des informations d'état pour un "FYI", mais cela peut être important dans certaines circonstances.

10
user565869

Sa préférence principalement

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

public class Result{
  public Person Person {get;set;}
  public int Sum {get;set;}
}
8
Scott Cowan

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

L’exception la plus notable qui me vienne à l’esprit concerne le fait de renvoyer plusieurs valeurs (.Net Framework n’a pas de n-uplets jusqu’à la version 4.0), comme avec le modèle TryParse.

5
Brian

Vous ne pouvez avoir qu'une seule valeur de retour alors que vous pouvez avoir plusieurs paramètres de sortie.

Vous devez uniquement prendre en compte les paramètres dans ces cas.

Cependant, si vous devez renvoyer plus d'un paramètre de votre méthode, vous voudrez probablement examiner ce que vous retournez avec une approche OO et déterminer si vous êtes mieux à même de retourner un objet ou une structure avec ceux-ci. paramètres. Par conséquent, vous revenez à une valeur de retour.

4
Robin Day

Je préférerais ce qui suit au lieu de ceux de cet exemple simple.

public int Value
{
    get;
    private set;
}

Mais, ils sont tous très semblables. Habituellement, on n'utilise 'out' que s'ils ont besoin de transmettre plusieurs valeurs de la méthode. Si vous voulez envoyer une valeur en entrée et en sortie de la méthode, choisissez 'ref'. Ma méthode est préférable si vous ne renvoyez qu'une valeur, mais si vous souhaitez transmettre un paramètre et obtenir une valeur, vous choisirez probablement votre premier choix.

2
kenny

Les deux ont un objectif différent et ne sont pas traités de la même manière par le compilateur. Si votre méthode doit renvoyer une valeur, vous devez utiliser return. Out est utilisé lorsque votre méthode doit renvoyer plusieurs valeurs.

Si vous utilisez return, les données sont d'abord écrites dans la pile de méthodes, puis dans celle de la méthode appelante. Alors que dans le cas de out, il est directement écrit dans la pile de méthodes appelantes. Je ne sais pas s'il y a d'autres différences.

1
danish

Il n'y a pas de réelle différence, les paramètres out sont en C # pour permettre à la méthode de renvoyer plus d'une valeur, c'est tout.

Cependant, il existe quelques légères différences, mais aucune d'entre elles n'est vraiment importante:

Utiliser le paramètre out vous obligera à utiliser deux lignes comme:

int n;
GetValue(n);

en utilisant la valeur de retour vous permettra de le faire en une seule ligne:

int n = GetValue();

Une autre différence (correcte uniquement pour les types de valeur et uniquement si C # ne met pas la fonction en ligne) est que l’utilisation de la valeur de retour fera nécessairement une copie de la valeur lorsque la fonction retour en utilisant le paramètre OUT ne le fera pas nécessairement.

1
user88637

L'utilisation du mot clé out avec un type de retour renvoyé peut parfois réduire le fardeau du code et améliorer la lisibilité. (Principalement lorsque les informations supplémentaires dans le paramètre out sont souvent ignorées.) Par exemple:

var result = DoThing();
if (result.Success)
{
    result = DoOtherThing()
    if (result.Success)
    {
        result = DoFinalThing()
        if (result.Success)
        {
            success = true;
        }
    }
}

contre:

var result;
if (DoThing(out result))
{
    if (DoOtherThing(out result))
    {
        if (DoFinalThing(out result))
        {
            success = true;
        }
    }
}
1
Paul Smith

Comme d’autres l’ont dit: retourne de la valeur, pas de sortie param.

Puis-je vous recommander le livre "Framework Design Guidelines" (2nd ed)? Les pages 184 à 185 couvrent les raisons pour lesquelles il faut éviter les paramètres. Tout le livre vous orientera dans la bonne direction sur toutes sortes de problèmes de codage .NET.

L'utilisation de l'outil d'analyse statique, FxCop, est associée aux directives de conception du framework. Vous le trouverez sur les sites de Microsoft en téléchargement gratuit. Exécutez ceci sur votre code compilé et voyez ce qu'il dit. S'il se plaint de centaines et de centaines de choses, ne paniquez pas! Regardez calmement et attentivement ce que cela dit à propos de chaque cas. Ne vous précipitez pas pour réparer les choses dès que possible. Apprenez de ce que cela vous dit. Vous serez mis sur le chemin de la maîtrise.

1
Andrew Webb

De plus, les valeurs de retour sont compatibles avec les paradigmes de conception asynchrones. 

Vous ne pouvez pas désigner une fonction "asynchrone" si elle utilise des paramètres ref ou out.

En résumé, Valeurs de retour autorisent le chaînage de méthodes, une syntaxe plus claire (en éliminant la nécessité pour l'appelant de déclarer des variables supplémentaires), et autorisent les conceptions asynchrones sans nécessiter de modification substantielle à l'avenir.

1
firetiger77

Je pense que l'un des rares scénarios où cela serait utile serait de travailler avec de la mémoire non gérée, et vous voulez indiquer qu'il est évident que la valeur "renvoyée" doit être supprimée manuellement, au lieu de l'attendre d'elle-même .

1
xian

out est plus utile lorsque vous essayez de retourner un objet que vous déclarez dans la méthode.

Exemple

public BookList Find(string key)
{
   BookList book; //BookList is a model class
   _books.TryGetValue(key, out book) //_books is a concurrent dictionary
                                     //TryGetValue gets an item with matching key and returns it into book.
   return book;
}
0
Taera Kwon

valeur de retour est la valeur normale renvoyée par votre méthode.

Où comme paramètre out, well out et ref sont deux mots clés de C #, ils permettent de passer des variables sous la forme reference

La grande différence entre ref et out est que ref doit être initialisé avant et out n'est pas

0
user2983359