web-dev-qa-db-fra.com

Quand devrais-je utiliser les paramètres?

Je ne comprends pas quand un paramètre de sortie doit être utilisé, personnellement, j'emballe le résultat dans un nouveau type si je dois renvoyer plusieurs types, je trouve qu'il est beaucoup plus facile de travailler qu'avec out.

J'ai vu une méthode comme celle-ci, 

   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 ne pas renvoyer un type ParseResult? ou dans le nouveau cadre retourner un type null-capable?

48
kay.one

Out est bon lorsque vous avez une fonction TryNNN et qu'il est clair que le paramètre out sera toujours défini, même si la fonction n'aboutit pas. Cela vous permet de compter sur le fait que la variable locale que vous déclarez sera définie plutôt que de devoir placer des contrôles ultérieurs dans votre code par rapport à null. (Un commentaire ci-dessous indique que le paramètre peut être défini sur null. Par conséquent, vous voudrez peut-être vérifier la documentation de la fonction que vous appelez pour savoir si c'est le cas ou non.) Le code est un peu plus clair et plus simple. lire. Un autre cas est lorsque vous devez renvoyer des données et un statut à 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 out. Certes, cet exemple est artificiel, car vous pouvez concevoir une méthode dans laquelle la fonction renvoie simplement un string, mais vous avez l’idée.

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

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

Au lieu de:

UpdateWithResult(DoSomething(5));

Cependant, cela peut ne pas être un inconvénient, cela dépend de la conception que vous allez adopter. Dans le cas de DateTime, les deux moyens (Parse et TryParse) sont fournis.

26
jasonh

Eh bien, comme dans la plupart des cas, cela dépend… .. Voyons les options

  • vous pouvez retourner ce que vous voulez comme valeur de retour de la fonction
  • si vous souhaitez renvoyer plusieurs valeurs ou si la fonction a déjà une valeur de retour, vous pouvez utiliser des paramètres externes ou créer un nouveau type composite qui expose toutes ces valeurs en tant que 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 représentant 16 milliards de frais généraux (sur les machines 32b), ni à payer le coût de leur récupération après l’appel. TryParse peut par exemple être appelé depuis une boucle. Les paramètres de sortie sont donc définis ici.
Pour les fonctions qui ne seraient pas appelées dans une boucle (c’est-à-dire que la performance n’est pas une préoccupation majeure), le retour d’un seul objet composite peut être plus propre (subjectif pour le spectateur). Désormais, avec les types anonymes et la saisie dynamique, cela pourrait devenir encore plus facile.

Remarque:

  1. Les paramètres out ont certaines règles à respecter, c'est-à-dire que le compilateur s'assurera que la fonction initialise la valeur avant de se fermer. Donc TryParse doit définir le paramètre out sur une valeur même si l'opération d'analyse a échoué
  2. Le modèle TryXXX est un bon exemple de l'utilisation des paramètres - Int32.TryParse a été introduit car des gens se sont plaints du piège des exceptions de capture pour savoir si l'analyse échouait. Aussi, la chose la plus probable que vous feriez si l'analyse réussissait, consistait à obtenir la valeur analysée. L'utilisation d'un paramètre out évite d'avoir à appeler une autre méthode avec Parse.
5
Gishu

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

bool isValid = int.TryParse("100", out int result = 0);
3
devuxer

Les paramètres out sont destinés à être utilisés lorsque vous avez une méthode qui doit renvoyer plusieurs valeurs, dans l'exemple que vous avez posté:

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

Il n’a pas de sens d’utiliser un paramètre out, car vous ne renvoyez qu’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 à propos des paramètres out:

  1. Les paramètres de sortie sont initialement considérés comme non affectés .
    • Chaque paramètre out doit doit être définitivement attribué avant le retour de la méthode, votre code ne sera pas compilé si vous manquez une affectation.

En conclusion, j'essaie essentiellement d'utiliser des paramètres dans mon private API pour éviter de créer des types distincts pour envelopper plusieurs valeurs de retour, et sur mon API publique, je ne les utilise que sur des méthodes qui correspondent au modèle TryParse.

2
CMS

Des années en retard avec une réponse, je sais que . Out (et ref) est également très utile si vous ne souhaitez pas que votre méthode instancie un nouvel objet à renvoyer. Ceci est très pertinent dans les systèmes hautes performances où vous souhaitez obtenir des performances inférieures à la microseconde pour votre méthode. l'instanciation est relativement coûteuse du point de vue de l'accès mémoire.

2

Créer un type juste pour renvoyer des valeurs me semble un peu pénible: -) Tout d'abord, je vais devoir créer un type pour renvoyer la valeur, puis dans la méthode d'appel, j'affecterai la valeur du type retourné à la variable réelle qui nécessite il. 

Les paramètres de sortie sont simples à utiliser.

0
chikak

Oui, cela a du sens. Prenez ceci par exemple.

String strNum = "-1";
Int32 outNum;

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

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

0
David Anderson

Cela ne m'ennuie pas que je ne puisse pas transmettre null au paramètre out pour les fonctions TryParse.

Néanmoins, je préfère dans certains cas renvoyer un nouveau type avec deux données. Surtout quand ils ne sont pas liés pour la plupart ou qu'une pièce n'est nécessaire que pour une seule opération, un instant après. Lorsque 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 aléatoire ResultAndValue que je dois gérer.

0
Spencer Ruport

J'utilise parfois des paramètres out pour des raisons de lisibilité, lorsque la lecture du nom de la méthode est plus importante que la sortie de la méthode, en particulier pour les méthodes qui exécutent des commandes en plus de renvoyer 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, j'insiste beaucoup sur les premiers caractères de chaque ligne lors de la numérisation. Je peux facilement dire ce qui se passe dans le premier exemple après avoir reconnu que certaines variables "StatusInfo" sont déclarées. Dans le deuxième exemple, la première chose que je vois est qu'un groupe de StatusInfo est récupéré. Je dois scanner une seconde fois pour voir quel genre d'effets les méthodes peuvent avoir.

0
Mark Cidade

Si vous créez toujours un type, vous pouvez vous retrouver avec beaucoup de fouillis dans votre application.

Comme indiqué ici, un cas d'utilisation typique est une méthode TrySomething dans laquelle vous souhaitez renvoyer une valeur booléenne en tant qu'indicateur de réussite, puis la valeur réelle. Je trouve également cela un peu plus propre dans une déclaration if - les trois options ont à peu près le même niveau de détail 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);
}

En ce qui concerne le "Pourquoi ne pas renvoyer un type Nullable": TryParse existe depuis Framework 1.x, alors que les types Nullable sont fournis avec la version 2.0 (car ils nécessitent des génériques). Alors, pourquoi rompre inutilement la compatibilité ou commencer à introduire des incohérences entre TryParse sur certains types? Vous pouvez toujours écrire votre propre méthode d’extension pour dupliquer une fonctionnalité déjà existante (voir Eric Lipperts Post sur un sujet non lié qui inclut un raisonnement derrière le fait de faire/ne pas faire des choses)

Un autre cas d'utilisation est le cas où vous devez renvoyer plusieurs valeurs non liées, même si cela doit déclencher une alarme indiquant que votre méthode en fait peut-être trop. D'autre part, si votre méthode ressemble à une base de données coûteuse ou à un appel de service Web et que vous souhaitez mettre en cache le résultat, il peut être judicieux de le faire. Bien sûr, vous pouvez créer un type, mais encore une fois, cela signifie un type supplémentaire dans votre application.

0
Michael Stum