Question

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 qui les séparent et je ne sais donc pas lequel est le meilleur. Pouvez-vous m'expliquer cela?

Merci.

Était-ce utile?

La solution

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 aucun des cas où je voudrais jamais une méthode void avec un paramètre out , si j'avais le choix. C <7 Les méthodes> Deconstruct pour la déconstruction prise en charge par la langue constituent une exception très rare à 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);

vs

int foo = GetValue();

Les valeurs de sortie 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 des régleurs de propriétés. 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 généralement 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, rien ne me dit qu'ils facilitent ...

...

Valeurs de retour FTW.

EDIT: En ce qui concerne ce qui se passe ...

En principe, lorsque vous passez un argument pour un "out". paramètre, vous devez passer une variable. (Les éléments de tableau sont également classés en tant que variables.) La méthode que vous appelez n'a pas de "nouveau". variable sur sa pile pour le paramètre - il 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 au "poste". étape - 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 valeur . Dans le test OutParameter, la variable value est modifiée par la ligne tmp = 10;

Autres conseils

Quoi de mieux, cela dépend de votre situation particulière. L'une des raisons pour lesquelles out existe est de 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 vous voudrez généralement utiliser une déclaration simple, à moins que vous ne rencontriez la situation ci-dessus, par exemple.

MODIFIER: Ceci est 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.

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.

Considérons ce que l’appelant de vos deux méthodes doit 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

Lorsque vous posez ce type de question, consultez les directives de conception du .NET Framework. Si vous avez la version du livre, vous pouvez voir les annotations d’Anders Hejlsberg et d’autres à 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 d'une API, les intégrer dans une structure / classe serait préférable à un paramètre out.

Il y a une raison d'utiliser un paramètre out qui n'a pas déjà été mentionné: la méthode appelante est obligée de le recevoir. Si votre méthode produit une valeur que l'appelant ne devrait pas ignorer, en faire une sortie oblige 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 entendu, l'appelant peut toujours ignorer la valeur dans un paramètre out , mais vous y avez attiré 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.

C'est la 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;}
}

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

L'exception la plus notable qui nous vient à l'esprit est lorsque vous souhaitez renvoyer plusieurs valeurs (.Net Framework n'a pas de nuplets avant la version 4.0), comme avec le modèle TryParse .

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.

Toutefois, si vous devez renvoyer plusieurs paramètres de votre méthode, vous voudrez probablement examiner ce que vous retournez d'une approche orientée objet et déterminer s'il vaut mieux renvoyer un objet ou une structure avec ces paramètres. . Par conséquent, vous revenez à une valeur de retour.

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.

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.

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’elles n’est vraiment importante:

L'utilisation du paramètre out vous obligera à utiliser deux lignes telles que:

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 de retour utilisant le paramètre OUT ne le fera pas nécessairement.

Comme d'autres l'ont déjà dit: renvoyer une valeur et non un paramètre sortant.

Puis-je vous recommander le livre "Framework Design Guidelines"? (2e éd)? 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.

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 faire en sorte que le "retourne" la valeur doit être éliminée manuellement, au lieu de s’attendre à ce qu’elle le soit elle-même.

De plus, les valeurs renvoyées sont compatibles avec les paradigmes de conception asynchrones.

Vous ne pouvez pas désigner une fonction " async " s'il utilise les paramètres ref ou out.

En résumé, les 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 modifications substantielles à l'avenir.

L'utilisation du mot clé out avec un type de retour bool 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;
        }
    }
}

vs:

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

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;
}

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

Où en tant que paramètre out , well out et ref sont deux mots clés de C # qui permettent de passer des variables en tant que référence .

La grande différence entre ref et sortie est que référence doit être initialisé avant et sortie ne pas

Je suppose que je ne vais pas consulter cette question, mais je suis un programmeur très expérimenté et j'espère que certains des lecteurs les plus ouverts vont y prêter attention.

Je pense que cela convient mieux aux langages de programmation orientés objet que leurs procédures de restitution de valeur (VRP) soient déterministes et pures.

'VRP' est le nom académique moderne d'une fonction appelée dans le cadre d'une expression. Sa valeur de retour remplace théoriquement l'appel lors de l'évaluation de l'expression. Par exemple. dans une instruction telle que x = 1 + f (y) , la fonction f sert de VRP.

"Déterministe" signifie que le résultat de la fonction dépend uniquement des valeurs de ses paramètres. Si vous l'appelez à nouveau avec les mêmes valeurs de paramètre, vous êtes certain d'obtenir le même résultat.

'Pure' signifie pas d'effets secondaires: appeler la fonction ne fait pas calculer le résultat. Cela peut être interprété comme signifiant aucun effet secondaire important , en pratique, donc si le VRP envoie un message de débogage à chaque appel, il peut probablement être ignoré, par exemple.

Ainsi, si, en C #, votre fonction n'est pas déterministe et pure, je vous conseille d'en faire une fonction void (en d'autres termes, pas un VRP), ainsi que toute valeur nécessaire return devrait être retourné dans un paramètre out ou ref .

Par exemple, si vous avez pour fonction de supprimer certaines lignes d'une table de base de données et si vous souhaitez qu'elle renvoie le nombre de lignes supprimées, vous devez le déclarer comme suit:

public void DeleteBasketItems (catégorie BasketItemCategory, out int count);

Si vous souhaitez parfois appeler cette fonction sans obtenir le nombre , vous pouvez toujours déclarer une surcharge.

Vous voudrez peut-être pourquoi ce style convient mieux à la programmation orientée objet. En gros, cela correspond à un style de programmation qui pourrait être (un peu imprécis) appelé "programmation procédurale". Il s'agit d'un style de programmation procédurale qui convient mieux à la programmation orientée objet.

Pourquoi? Le modèle classique des objets est qu'ils ont des propriétés (ou attributs) et que vous interrogez et manipulez l'objet (principalement) en lisant et en mettant à jour ces propriétés. Ceci est facilité par un style de programmation procédurale, car vous pouvez exécuter du code arbitraire entre les opérations qui obtiennent et définissent les propriétés.

L’inconvénient de la programmation procédurale est que, du fait que vous pouvez exécuter du code arbitraire partout, vous pouvez obtenir des interactions très obtuses et vulnérables aux bogues via des variables globales et des effets secondaires.

Donc, tout simplement, il est judicieux de signaler à une personne lisant votre code qu'une fonction pourrait avoir des effets secondaires en la rendant non renvoyée par la valeur.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top