Je vois le modèle de code suivant partout dans la base de code de mon entreprise (application .NET 3.5):
bool Foo(int barID, out Baz bazObject) {
try {
// do stuff
bazObject = someResponseObject;
return true;
}
catch (Exception ex) {
// log error
return false;
}
}
// calling code
BazObject baz = new BazObject();
fooObject.Foo(barID, out baz);
if (baz != null) {
// do stuff with baz
}
J'essaie de comprendre pourquoi vous feriez cela au lieu d'avoir la Foo
méthode simplement prendre l'ID et renvoyer un Baz
objet, au lieu de renvoyer une valeur qui n'est pas utilisée et que l'objet réel soit un paramètre de référence ou de sortie.
Y a-t-il un avantage caché de ce style de codage qui me manque?
c#
code-quality
coding-style
Wayne Molina
la source
la source
baz
êtrenull
et l'bool
être retourné nefalse
sont pas équivalents.new BazObject()
n'est jamaisnull
, donc à moins qu'il nebazObject
soit mis à jour avant que leException
soit jetéFoo
, quandfalse
est retournébaz
ne le sera jamaisnull
. Cela aiderait énormément si les spécifications pourFoo
étaient disponibles. En fait, c'est peut-être le problème le plus grave présenté par ce code.Réponses:
Vous utilisez généralement ce modèle pour pouvoir écrire du code comme ceci:
il est utilisé dans le CLR pour TryGetValue dans la classe de dictionnaire par exemple. Cela évite une certaine redondance mais les paramètres out et ref me semblaient toujours un peu compliqués
la source
Il s'agit d'un ancien code de style C, avant qu'il n'y ait des exceptions. La valeur renvoyée indiquait si la méthode avait réussi ou non, et si c'était le cas, le paramètre serait rempli avec le résultat.
Dans .net, nous avons des exceptions à cet effet. Il ne devrait y avoir aucune raison de suivre ce modèle.
[modifier] Il y a évidemment des implications de performances dans la gestion des exceptions. Peut-être que ceci a quelque chose à y voir. Cependant, dans cet extrait de code, une exception est déjà levée. Il serait plus propre de simplement le laisser remonter la pile jusqu'à ce qu'il soit pris dans un endroit plus approprié.
la source
if (baz.Select())
mais le plus souvent, la valeur de retour est simplement jetée et la valeur est vérifiée par rapport à null ou à une propriété.Étant donné l'extrait de code, il semble complètement inutile. Pour moi, le modèle de code initial suggérerait que null pour BazObject serait un cas acceptable et le retour booléen est une mesure pour déterminer un cas d'échec en toute sécurité. Si le code suivant était:
Cela aurait plus de sens pour moi de procéder de cette façon. C'est peut-être une méthode que quelqu'un avant vous utilisait pour garantir que baz était passé par référence sans comprendre comment les paramètres d'objet fonctionnent réellement en C #.
la source
Parfois, ce modèle est utile lorsque vous, l'appelant, n'êtes pas censé vous soucier de savoir si le type retourné est un type de référence ou de valeur. Si vous appelez une telle méthode pour récupérer un type de valeur, ce type de valeur aura besoin d'une valeur non valide établie (par exemple, double.NaN), ou vous avez besoin d'une autre manière de déterminer le succès.
la source
L'idée est de renvoyer une valeur qui indique si le processus a réussi, en autorisant un code comme celui-ci:
Si l'objet ne peut pas être nul (ce qui semble correct dans votre exemple), il vaut mieux procéder comme suit:
Si l'objet peut être nul, les exceptions sont la voie à suivre:
C'est un modèle commun utilisé en C, où il n'y a pas d'exceptions. Il permet à la fonction de renvoyer une condition d'erreur. Les exceptions sont généralement une solution beaucoup plus propre.
la source