11
votes

Quel est le problème avec les paramètres de sortie?

à la fois en SQL et C #, je n'ai jamais vraiment aimé les paramètres de sortie. Je n'ai jamais passé les paramètres BYREF dans VB6, non plus. Quelque chose à propos de compter sur des effets secondaires pour que quelque chose me dérange juste me dérange.

Je sais qu'ils sont un moyen de ne pas pouvoir retourner plusieurs résultats d'une fonction, mais une ligne de données dans SQL ou un type de données complexe en C # et VB travaillent aussi bien, et semblent plus auto-documentant pour moi. < / p>

Y a-t-il quelque chose qui ne va pas avec ma pensée, ou existe-t-il des ressources provenant de sources autoritations qui me soutiennent? Quelle est votre prise personnelle sur cela et pourquoi? Que puis-je dire aux collègues qui souhaitent concevoir des paramètres de sortie susceptibles de les convaincre d'utiliser différentes structures?

Edit: Turn intéressant - Le paramètre de sortie que je posais cette question sur cette question a été utilisé à la place d'une valeur de retour. Lorsque la valeur de retour est "Erreur", l'appelant est censé le gérer comme une exception. Je faisais ça mais pas content de l'idée. Un collègue n'a pas été informé de la nécessité de gérer cette condition et, par conséquent, beaucoup d'argent ont été perdus car la procédure a échoué silencieusement!


5 commentaires

Ceci est subjectif et devrait être un wiki communautaire pour une existence continue. Je note qu'il y a déjà un coup de fermeture. Je ne fermerai pas si vous ne le marquez pas cw.


Qu'est-ce que je sais, mais cela me semble une bonne question sur les compromis de conception.


Tags modifiés pour inclure les références SQL + VB dans les questions


@Randolpho, si je modifie la question pour inclure un exemple spécifique et demander de l'aide refactoring, cela le rendrait-il moins subjectif?


Nah, c'est bien comme ça. À la deuxième lecture, j'ai eu un peu trop anal. :)


11 Réponses :


28
votes

Les paramètres de sortie peuvent être une odeur de code indiquant que votre méthode fait trop. Si vous avez besoin de retourner plus d'une valeur, la méthode va probablement faire plus d'une chose. Si les données sont étroitement liées, cela bénéficierait probablement d'une classe qui détient les deux valeurs.

Bien sûr, ce n'est pas toujours le cas, mais j'ai constaté que c'est généralement le cas.

En d'autres termes, je pense que vous avez raison de les éviter.


0 commentaires

0
votes

Je ne les utilise généralement jamais, je pense qu'ils sont déroutants et trop faciles à abuser. Nous utilisons parfois des paramètres de référence, mais cela a plus à voir avec le passage dans des structures vs. Les récupérer.


0 commentaires

0
votes

Votre avis vous semble raisonnable pour moi.

Un autre inconvénient de paramètres de sortie est le code supplémentaire nécessaire pour réussir les résultats d'une fonction à une autre. Vous devez déclarer la ou les variable (s), appelez la fonction pour obtenir leurs valeurs, puis transmettez les valeurs à une autre fonction. Vous ne pouvez pas simplement nier les appels de fonction. Cela rend le code lu très impérieusement, plutôt que déclarative.


0 commentaires

11
votes

Bob Martin a écrit à propos de ce code propre. Les paramètres de sortie rompent l'idée fondamentale d'une fonction.

sortie = SOMEMETHOD (entrée)


2 commentaires

Un processus stocké n'est pas une fonction cependant, mais je comprends le raisonnement


On dirait que le lien vers Bob Martin est maintenant mort.



1
votes

Je pense qu'ils sont utiles pour obtenir des identifiants de lignes nouvellement insérées dans la même commande SQL, mais je ne pense pas que je ne les utilisiez pas pour beaucoup d'autre.


0 commentaires

0
votes

C ++ 0x obtient des tuples, une chose de type structure anonyme, dont vous accédez aux membres par index. Les programmeurs C ++ pourront emballer plusieurs valeurs dans l'une de ces personnes et le renvoyer. C # a quelque chose comme ça? Peut-il retourner un tableau, peut-être, à la place? Mais les paramètres de sortie YEAH sont un peu maladroits et peu clairs.


3 commentaires

C # peut retourner un tableau facilement. Mais retourner un tableau (ce qui est essentiellement ce que le tuple est aussi bien) me semble assez sémantique et peut facilement être déroutant. Si vous retournez toujours le même ensemble de valeurs, les variables sont un meilleur choix pour moi.


C # 4.0 présentera une caractéristique très innovante ... le tuple :)


.NET 4.0 a tuple classe, mais il n'y a pas de support de langue pour cela. C ++ 0x n'en a pas non plus, mais il dispose de constructions linguistiques pour couvrir, par exemple, la déconstruction de tuple. Par exemple, avec des tuples C ++ 0x, vous pouvez faire: tuple t; int a, b; cravate (a, b) = t; . Dans C #, vous devrez faire: a = t.item1; b = t.item2 .



20
votes

Ils ont leur place. La méthode Int32.Tryparse est un bon exemple d'utilisation efficace d'un paramètre OUT.

bool result = Int32.TryParse(value, out number);
if (result)
{
    Console.WriteLine("Converted '{0}' to {1}.", value, number);         
}


10 commentaires

Bon exemple. La trypairse est l'une des seules méthodes que j'ai jamais constatées qui utilise et est justifiée.


C'est un cas particulier intéressant, car Tryparse () existe pour éviter la possibilité d'une exception lorsque la valeur ne contient pas d'int.


Je préférerais personnellement "int? Int32.tryparse (valeur de chaîne)" comme signature, car vous pouvez alors utiliser le ?? opérateur de spécifier les valeurs de repli. Mais cette fonction a été écrite avant l'introduction des Nullables.


Je suis en désaccord ... int32.tryparse () devrait renvoyer un int? Toute méthode TRY * doit renvoyer un type nullable ... il se lit mieux et il est plus facile à utiliser. Je crée des méthodes d'extension pour la chaîne qui font exactement cela. "1" .Asint (), "1.5" .asdouble (), "vrai" .ASbool () etc.


Il n'y a pas de différence fondamentale entre le retour d'un int? et renvoyer un int + BOOL combo (dont l'un est dans un paramètre). C'est surtout une question de commodité.


@Pavel: Je pense que la différence significative est qu'avec un paramètre Out, la variable doit être déclarée séparément. Toute chance que je dois réduire le nombre de variables temporaires est une chance de rendre mon code plus lisible, qui est une victoire dans mes livres :)


En fait, INT32.TRYPARSE est apparu dans .NET 2.0, en même temps que NULLLABLE , ce qui rend d'autant plus perplexe qu'ils ne fonctionnent pas ensemble. Mais vous pouvez toujours écrire votre propre fonction pour le faire.


Un autre exemple est le dictionnaire <,>. Trygetvalue


Même avec "int? Int32.tryparse (valeur de chaîne)" Vous devez toujours écrire une variable à l'avance pour faire des choses comme si (Int.tryparse (...) {...}, Mais maintenant vous devez faire un chèque null "Int? res = int.tryparse (...); si (res! = null) afin que les deux implémentations ont leurs avantages.


La plupart du temps lorsque j'ai besoin de vérifier si une chaîne est analysée correctement vers un autre type, je me souciais de la valeur. Donc, je ne vois aucune valeur dans l'utilisation de cette entreprise Bool Tryparse (Out). Même dans le cas rare, vous ne vous souciez pas de la valeur et que vous vouliez écrire du code laid, si (int.trypsarse (s) .hasvalue) fonctionnerait très bien.



1
votes

Je vois aussi très peu d'utilisation de paramètres OUT / REF, bien que dans SQL, il soit parfois plus facile de passer une valeur de retour d'un paramètre que par un résultateur (qui nécessiterait alors l'utilisation d'un digne d'information, etc.)

Cependant, comme la chance l'aurait, je viens de créer une de ces fonctions rares dans C # aujourd'hui. Il validait une structure de données semblable à une table et renvoya le nombre de lignes et de colonnes (qui était difficile à calculer car la table pourrait avoir des rangées / cols-cols comme dans HTML). Dans ce cas, le calcul des deux valeurs a été effectué en même temps. La séparer en deux fonctions aurait entraîné deux fois les exigences de temps de code, de mémoire et de processeur. Créer un type personnalisé juste pour cette fonction de retour semble aussi être un overkill pour moi.

Donc, il y a des moments où ils sont la meilleure chose, mais surtout, vous pouvez faire très bien sans eux.


0 commentaires

1
votes

the sortie clause SQL Server 2005 En 2005 est un grand pas en avant pour obtenir des valeurs de champ pour les lignes concernées par vos déclarations DML. Ithink qu'il y a beaucoup de situations où cela s'éloigne des paramètres de sortie.

Dans VB6, les paramètres BYREF sont bons pour passer des objets ADO autour.

Autre que ces deux cas spécifiques qui nous viennent à l'esprit, j'ai tendance à éviter de les utiliser.


0 commentaires

1
votes

en SQL seulement ...

Procédure stockée Les paramètres de sortie sont utiles.

  1. Dites que vous avez besoin d'une valeur de retour. Avez-vous "Créer #table, insérer ... EXEC, SELECT @VAR =". Ou utilisez un paramètre de sortie?

  2. Pour les appels du client, un paramètre de sortie est beaucoup plus rapide que le traitement d'un jeu d'enregistrements.

  3. L'utilisation de valeurs de retour est limitée à un entier signé.

  4. plus facile à réutiliser (par exemple, une procédure d'assistance de vérification de sécurité)

  5. Lorsque vous utilisez les deux: Recettes = données, paramètres de sortie = État / messages / RowCount, etc.

  6. Les procédures stockées Sortie des enregistrements d'enregistrement ne peuvent pas être fortement typées comme UDF ou code client

  7. Vous ne pouvez pas toujours utiliser un UDF (p. ex. journalisation lors du contrôle de sécurité ci-dessus)

    Cependant, tant que vous n'utilisez généralement pas le même paramètre pour entrer et sortir, puis jusqu'à ce que SQL change complètement vos options soient limitées. En disant que, j'ai un cas où j'utilise un paramètre pour les valeurs intestines et sortantes, mais j'ai une bonne raison.


0 commentaires

1
votes

Mes deux cents:
Je conviens que les paramètres de sortie sont une pratique en matière de pratique. La VBA est souvent maintenue par des personnes très nouvelles pour la programmation et si une personne qui maintient votre code ne remarque pas qu'un paramètre est de byref, ils pourraient introduire des erreurs logiques sérieuses. En outre, il a tendance à casser la propriété / la fonction / sub paradigme.
Une autre raison que l'utilisation de paramètres est une mauvaise pratique est que si vous avez vraiment les devez revenir plus d'une valeur, les chances sont que vous devez avoir ces valeurs dans une structure de données telle qu'une classe ou un utilisateur Type défini.
Ils peuvent toutefois résoudre certains problèmes. VB5 (et donc VBA pour Office 97) ne permettait pas à une fonction de renvoyer une matrice. Cela signifiait que quelque chose de retourner ou de modifier une matrice devrait le faire via un paramètre «Out». Dans VB6, cette capacité a été ajoutée, mais VB6 force toujours des paramètres de tableau pour être en référence (pour éviter une copie excessive en mémoire). Maintenant, vous peut retourner une valeur d'une fonction qui modifie une matrice. Mais ce ne sera qu'un cheveu lent (en raison des acrobaties qui se passent dans les coulisses); Il peut également confondre les débutants à penser que l'entrée de la matrice ne sera pas modifiée (ce qui ne sera vrai que si une personne la structurée spécifiquement de cette façon). Donc, je trouve que si j'ai une fonction qui modifie un tableau, il réduit la confusion pour simplement utiliser un sous-sol au lieu d'une fonction (et ce sera un peu plus rapide aussi).
Un autre scénario possible serait si vous conservez du code et que vous souhaitez ajouter une valeur de sortie sans casser l'interface que vous peut ajouter un paramètre Out Out Out optionnel et être confiant, vous ne briserez aucun code ancien. Ce n'est pas une bonne pratique, mais si quelqu'un veut que quelque chose répète en ce moment et que vous n'avez pas le temps de le faire de la "bonne façon" et de tout restructurer, cela peut être un ajout pratique à votre boîte à outils.
Toutefois, si vous développez des choses à la terre et vous devez retourner plusieurs valeurs que vous devriez envisager:
1. Briser la fonction.
2. Renvoyer un UDT.
3. Renvoyer une classe.


0 commentaires