Quand dois-je utiliser les paramètres de sortie?

Je ne comprends pas quand un paramètre de sortie doit être utilisé, j'enroule personnellement le résultat dans un nouveau type si j'ai besoin de retourner plus d'un type, je trouve que beaucoup plus facile de travailler avec que sur.

j'ai vu méthode comme ceci,

   public void Do(int arg1, int arg2, out int result)

existe-t-il des cas où cela a du sens?

Que diriez-vous de TryParse, pourquoi pas le retour d'un ParseResult type? ou dans le nouveau framework retourner un type null-able?

44
demandé sur Motti 2009-07-23 09:36:46

10 réponses

Out est bon lorsque vous avez un TryNNN fonction et il est clair que le paramètre sera toujours ensemble, même si la fonction ne pas réussir. Cela vous permet de vous fier au fait que la variable locale que vous déclarez sera définie plutôt que d'avoir à placer des vérifications plus tard dans votre code contre null. (Un commentaire ci-dessous indique que le paramètre peut être réglé sur null, donc vous pouvez vérifier la documentation de la fonction que vous appelez pour être sûr que ce soit le cas ou non.) le code un peu plus clair et plus facile à lire. Un autre cas est quand vous avez besoin de retourner quelques données et un statut sur la condition de la méthode comme:

public bool DoSomething(int arg1, out string result);

Dans ce cas, le retour peut indiquer si la fonction a réussi et le résultat est stocké dans le paramètre de sortie. Certes, cet exemple est inventé parce que vous pouvez concevoir un chemin où la fonction renvoie simplement un string, mais vous obtenez l'idée.

Un inconvénient est que vous devez déclarer une variable locale à utiliser:

string result;
if (DoSomething(5, out result))
    UpdateWithResult(result);

au Lieu de:

UpdateWithResult(DoSomething(5));

cependant, ce n'est peut-être même pas un inconvénient, cela dépend de la conception que vous visez. Dans le cas de DateTime, les deux moyens (Parse et TryParse) sont fournis.

26
répondu jasonh 2009-07-23 08:30:45

comme pour la plupart des choses, cela dépend. Regardons les options

  • vous pouvez retourner ce que vous voulez comme valeur de retour de la fonction
  • si vous voulez retourner plusieurs valeurs ou si la fonction a déjà une valeur de retour, vous pouvez soit utiliser des params ou créer un nouveau type composite qui expose toutes ces valeurs comme propriétés

dans le cas de TryParse, l'utilisation d'un paramètre out est efficace - vous n'avez pas à créer un nouveau type serait 16B de frais généraux (sur des machines 32b) ou encourir Le coût de perf de leur collecte des ordures post l'appel. TryParse peut être appelé de l'intérieur d'une boucle par exemple - so out params règle ici.

Pour les fonctions qui ne seraient pas appelées dans une boucle (c.-à-d. la performance n'est pas une préoccupation majeure), retourner un seul objet composite pourrait être "propre" (subjectif à l'observateur). Maintenant avec les types anonymes et la dactylographie dynamique, il pourrait devenir Pair facile.

Remarque:

  1. out params ont certaines règles qui doivent être suivies, c'est-à-dire que le compilateur veillera à ce que la fonction initialise la valeur avant de la quitter. Donc TryParse doit définir le paramètre out à une certaine valeur même si l'opération parse a échoué
  2. le modèle TryXXX est un bon exemple de quand utiliser out params - Int32.TryParse a été présenté parce que les gens se sont plaints de la perf hit de la capture des exceptions pour savoir si parse a échoué. Également la chose la plus probable que vous feriez dans le cas où parse réussi, est d'obtenir la valeur parsée - en utilisant un param signifie que vous n'avez pas à faire un autre appel de méthode pour Parse
5
répondu Gishu 2009-07-23 09:23:54

je pense que out est utile pour les situations où vous devez retourner à la fois un booléen et une valeur, comme TryParse, mais ce serait bien si le compilateur permettait quelque chose comme ceci:

bool isValid = int.TryParse("100", out int result = 0);
3
répondu devuxer 2009-07-23 05:53:44

Certainement, les paramètres de sortie sont destinés à être utilisés lorsque vous avez une méthode qui doit renvoyer qu'une seule valeur, dans l'exemple que vous avez posté:

public void Do(int arg1, int arg2, out int result)

cela n'a pas beaucoup de sens d'utiliser un paramètre out, puisque vous retournez seulement une valeur, et cette méthode pourrait être mieux utilisée si vous supprimez le paramètre out et mettez une valeur de retour int:

public int Do(int arg1, int arg2)

Il y a quelques bonnes choses au sujet de paramètres:

  1. les paramètres de sortie sont initialement considéré comme non assigné.
    • Chaque paramètre être définitivement assigné avant le retour de la méthode, votre code ne sera pas compilé si vous manquez une tâche.

en conclusion, j'essaie d'utiliser des params dans mon private API pour éviter de créer des types séparés pour envelopper des valeurs de retour multiples, et sur mon API publique, Je ne les utilise que sur les méthodes qui correspondent au motif TryParse.

2
répondu CMS 2009-07-23 06:04:09

années de retard avec une réponse, je sais. (ref) est également très utile si vous ne souhaitez pas que votre méthode ne instancier un nouvel objet de retour. Ceci est très important dans les systèmes à haute performance où vous voulez obtenir des performances sub microsecondes pour votre méthode. l'instanciation est relativement coûteuse du point de vue de l'accès à la mémoire.

1
répondu ThomasVestergaard 2015-10-08 21:11:46

créer un type juste pour retourner des valeurs semble un peu douloureux pour moi :-) D'abord je vais devoir créer un type pour retourner la valeur puis dans la méthode d'appel j'ai assigné la valeur du type retourné à la variable réelle qui en a besoin.

les paramètres Out sont simipler à utiliser.

0
répondu chikak 2009-07-23 05:40:29

Oui, c'est logique. Profiter de cette par exemple.

String strNum = "-1";
Int32 outNum;

if (Int32.TryParse(strNum, out outNum)) {
    // success
}
else {
    // fail
}

Que pouvez-vous retourner si l'opération échoue dans une fonction normale avec une valeur de retour? Vous ne pourriez certainement pas retourner -1 pour représenter un échec, parce qu'il n'y aurait alors aucune différence entre la valeur de retour d'échec et la valeur réelle qui a été analysée pour commencer. C'est pourquoi nous retournons une valeur booléenne pour voir si elle a réussi, et si elle a réussi alors nous avons notre valeur" return " assignée en toute sécurité déjà.

0
répondu David Anderson 2009-07-23 05:42:01

cela m'ennuie que je ne puisse pas passer en null au paramètre out pour les fonctions TryParse.

pourtant, je préfère dans certains cas retourner un nouveau type avec deux données. Surtout quand ils ne sont pas liés pour la plupart ou une pièce est seulement nécessaire pour une seule opération un moment après. Quand j'ai besoin de sauvegarder la valeur résultante d'une fonction TryParse, j'aime vraiment avoir un paramètre out plutôt qu'une classe de résultat et de valeur aléatoire que je dois gérer. avec.

0
répondu Spencer Ruport 2009-07-23 05:42:40

si vous créez toujours un type, alors vous pouvez finir avec beaucoup d'encombrement dans votre application.

comme dit ici, un cas d'utilisation typique est un TrySomething Méthode où vous voulez retourner un booléen comme un indicateur de succès et la valeur réelle. Je trouve aussi que c'est un peu plus propre dans un if-statement - les trois options ont à peu près la même LOC de toute façon.

int myoutvalue;
if(int.TryParse("213",out myoutvalue){
    DoSomethingWith(myoutvalue);
}

vs.

ParseResult<int> myoutvalue = int.TryParse("213");
if ( myoutvalue.Success ) {
    DoSomethingWith(myoutvalue.Value);
}

vs.

int? myoutvalue = int.TryParse("213");
if(myoutvalue.HasValue){
    DoSomethingWith(myoutvalue.Value);
}

Comme pour les "Pourquoi pas le retour d'un Type Nullable": TryParse existe depuis Cadre 1.x, alors que Nullable Les Types sont venus avec 2.0 (comme ils exigent des génériques). Alors pourquoi rompre la compatibilité sans raison ou commencer à introduire des incohérences entre TryParse sur certains types? Vous pouvez toujours écrire votre propre méthode d'extension pour dupliquer des fonctionnalités déjà existantes (voir Eric Lipperts Post sur un sujet sans rapport qui comprend un certain raisonnement derrière faire/ne pas faire des choses)

un autre cas d'utilisation est si vous devez retourner plusieurs valeurs non liées, même si vous faites cela qui devrait déclenchez une alarme que votre méthode est peut-être trop faire. D'un autre côté, si votre méthode est quelque chose comme une base de données coûteuse ou appel de service web et que vous voulez mettre en cache le résultat, il peut être logique de le faire. Bien sûr, vous pouvez créer un type, mais encore une fois, cela signifie un type de plus dans votre application.

0
répondu Michael Stum 2009-07-23 06:01:08

j'utilise paramètres parfois pour la lisibilité, lors de la lecture du nom de la méthode est plus important que tout ce que la sortie de la méthode est-en particulier pour les méthodes qui exécutent des commandes en plus de retourner des résultats.

StatusInfo a, b, c;

Initialize(out a);
Validate(a, out b);
Process(b, out c);

vs.

StatusInfo a = Initialize();
StatusInfo b = Validate(a);
StatusInfo c = Process(b);

au moins pour moi, je mets beaucoup d'emphase sur les premiers caractères de chaque ligne quand je scanne. Je peux facilement dire ce qui se passe dans le premier exemple après avoir reconnu que certains Les variables "StatusInfo" sont déclarées. Dans le deuxième exemple, la première chose que je vois est qu'un tas de StatusInfo est extrait. Je scanner une deuxième fois pour voir quel genre d'effets que ces méthodes ont.

0
répondu Mark Cidade 2009-07-23 07:48:49