C'est une sorte de question générale (mais j'utilise C #), quelle est la meilleure façon (meilleure pratique), renvoyez-vous une collection nulle ou vide pour une méthode qui a une collection comme type de retour?
c#
collections
Omu
la source
la source
Réponses:
Collection vide. Toujours.
Cela craint:
Il est considéré comme une meilleure pratique de ne JAMAIS retourner
null
lors du retour d'une collection ou d'un énumérable. TOUJOURS retourner une collection / énumérable vide. Il empêche les absurdités susmentionnées et empêche votre voiture d'être incitée par les collègues et les utilisateurs de vos classes.Lorsque vous parlez de propriétés, définissez toujours votre propriété une fois et oubliez-la
Dans .NET 4.6.1, vous pouvez condenser cela beaucoup:
Lorsque vous parlez de méthodes qui renvoient des énumérateurs, vous pouvez facilement renvoyer un énumérateur vide au lieu de
null
...L'utilisation
Enumerable.Empty<T>()
peut être considérée comme plus efficace que le retour, par exemple, d'une nouvelle collection ou d'un tableau vide.la source
IEnumerable
ouICollection
non. Quoi qu'il en soit, si vous sélectionnez quelque chose de type,ICollection
ils reviennent égalementnull
... J'aimerais qu'ils retournent une collection vide, mais je les ai rencontrés en retournull
, alors j'ai pensé que je le mentionnerais ici. Je dirais que la valeur par défaut d'une collection d'énumérables est vide et non nulle. Je ne savais pas que c'était un sujet aussi sensible.Extrait des Framework Design Guidelines 2nd Edition (p. 256):
Voici un autre article intéressant sur les avantages de ne pas retourner de null (j'essayais de trouver quelque chose sur le blog de Brad Abram, et il avait un lien vers l'article).
Edit- comme Eric Lippert a maintenant commenté la question d'origine, je voudrais également faire un lien vers son excellent article .
la source
Cela dépend de votre contrat et de votre cas concret . En règle générale, il est préférable de renvoyer les collections vides , mais parfois ( rarement ):
null
pourrait signifier quelque chose de plus spécifique;null
.Quelques exemples concrets:
null
cela signifierait que l'élément est manquant, tandis qu'une collection vide rendrait un élément redondant (et peut-être incorrect)<collection />
la source
Il y a un autre point qui n'a pas encore été mentionné. Considérez le code suivant:
Le langage C # renverra un énumérateur vide lors de l'appel de cette méthode. Par conséquent, pour être cohérent avec la conception du langage (et donc les attentes du programmeur), une collection vide doit être retournée.
la source
Le vide est beaucoup plus convivial pour le consommateur.
Il existe une méthode claire pour créer un énumérable vide:
la source
Il me semble que vous devez renvoyer la valeur sémantiquement correcte dans son contexte, quelle qu'elle soit. Une règle qui dit "toujours retourner une collection vide" me semble un peu simpliste.
Supposons, par exemple, dans un système pour un hôpital, que nous ayons une fonction qui est censée renvoyer une liste de toutes les hospitalisations précédentes au cours des 5 dernières années. Si le client n'est pas allé à l'hôpital, il est judicieux de renvoyer une liste vide. Mais que se passe-t-il si le client laisse cette partie du formulaire d'admission vierge? Nous avons besoin d'une valeur différente pour distinguer "liste vide" de "pas de réponse" ou "ne sait pas". Nous pourrions lever une exception, mais ce n'est pas nécessairement une condition d'erreur, et cela ne nous exclut pas nécessairement du flux de programme normal.
J'ai souvent été frustré par des systèmes qui ne peuvent pas faire la distinction entre zéro et aucune réponse. J'ai eu un certain nombre de fois où un système m'a demandé d'entrer un certain nombre, j'entre zéro et je reçois un message d'erreur me disant que je dois entrer une valeur dans ce champ. Je viens de le faire: je suis entré à zéro! Mais il n'acceptera pas zéro car il ne peut le distinguer d'aucune réponse.
Répondre à Saunders:
Oui, je suppose qu'il y a une différence entre «La personne n'a pas répondu à la question» et «La réponse était zéro». C'était le point du dernier paragraphe de ma réponse. De nombreux programmes sont incapables de distinguer «ne sait pas» de vide ou zéro, ce qui me semble être une faille potentiellement grave. Par exemple, je cherchais une maison il y a environ un an. Je suis allé sur un site Web immobilier et il y avait beaucoup de maisons répertoriées avec un prix demandé de 0 $. Cela me semblait plutôt bien: ils donnent ces maisons gratuitement! Mais je suis sûr que la triste réalité était qu'ils n'avaient tout simplement pas entré le prix. Dans ce cas, vous pouvez dire: «Eh bien, bien sûr, zéro signifie qu'ils n'ont pas entré le prix - personne ne va céder une maison gratuitement». Mais le site a également répertorié les prix moyens de vente et de demande des maisons dans diverses villes. Je ne peux pas m'empêcher de me demander si la moyenne n'a pas inclus les zéros, donnant ainsi une moyenne incorrectement faible pour certains endroits. c'est-à-dire quelle est la moyenne de 100 000 $; 120 000 $; et "je ne sais pas"? Techniquement, la réponse est "ne sais pas". Ce que nous voulons probablement vraiment, c'est 110 000 $. Mais ce que nous obtiendrons probablement, c'est 73 333 $, ce qui serait complètement faux. Et si nous avions ce problème sur un site où les utilisateurs peuvent commander en ligne? (Peu probable pour l'immobilier, mais je suis sûr que vous l'avez vu pour de nombreux autres produits.) Voudrions-nous vraiment que "prix non spécifié pour le moment" soit interprété comme "gratuit"? donnant ainsi une moyenne incorrectement faible pour certains endroits. c'est-à-dire quelle est la moyenne de 100 000 $; 120 000 $; et "je ne sais pas"? Techniquement, la réponse est "ne sais pas". Ce que nous voulons probablement vraiment, c'est 110 000 $. Mais ce que nous obtiendrons probablement, c'est 73 333 $, ce qui serait complètement faux. Et si nous avions ce problème sur un site où les utilisateurs peuvent commander en ligne? (Peu probable pour l'immobilier, mais je suis sûr que vous l'avez vu pour de nombreux autres produits.) Voudrions-nous vraiment que "prix non spécifié pour le moment" soit interprété comme "gratuit"? donnant ainsi une moyenne incorrectement faible pour certains endroits. c'est-à-dire quelle est la moyenne de 100 000 $; 120 000 $; et "je ne sais pas"? Techniquement, la réponse est "ne sais pas". Ce que nous voulons probablement vraiment, c'est 110 000 $. Mais ce que nous obtiendrons probablement, c'est 73 333 $, ce qui serait complètement faux. Et si nous avions ce problème sur un site où les utilisateurs peuvent commander en ligne? (Peu probable pour l'immobilier, mais je suis sûr que vous l'avez vu pour de nombreux autres produits.) Voudrions-nous vraiment que "prix non spécifié pour le moment" soit interprété comme "gratuit"? ce qui serait complètement faux. Et si nous avions ce problème sur un site où les utilisateurs peuvent commander en ligne? (Peu probable pour l'immobilier, mais je suis sûr que vous l'avez vu pour de nombreux autres produits.) Voudrions-nous vraiment que "prix non spécifié pour le moment" soit interprété comme "gratuit"? ce qui serait complètement faux. Et si nous avions ce problème sur un site où les utilisateurs peuvent commander en ligne? (Peu probable pour l'immobilier, mais je suis sûr que vous l'avez vu pour de nombreux autres produits.) Voudrions-nous vraiment que "prix non spécifié pour le moment" soit interprété comme "gratuit"?
RE ayant deux fonctions distinctes, un "y en a-t-il?" et un "si oui, qu'est-ce que c'est?" Oui, vous pourriez certainement le faire, mais pourquoi voudriez-vous? Maintenant, le programme appelant doit passer deux appels au lieu d'un. Que se passe-t-il si un programmeur ne parvient pas à appeler le "tout?" et va directement au "qu'est-ce que c'est?" ? Le programme renverra-t-il un zéro erroné? Jetez une exception? Renvoyer une valeur indéfinie? Il crée plus de code, plus de travail et plus d'erreurs potentielles.
Le seul avantage que je vois est qu'il vous permet de vous conformer à une règle arbitraire. Y a-t-il un avantage à cette règle qui vaut la peine de lui obéir? Sinon, pourquoi s'embêter?
Répondre à Jammycakes:
Considérez à quoi ressemblerait le code réel. Je sais que la question a dit C # mais excusez-moi si j'écris Java. Mon C # n'est pas très net et le principe est le même.
Avec un retour nul:
Avec une fonction distincte:
C'est en fait une ligne ou deux de moins avec le retour nul, donc ce n'est pas plus de fardeau pour l'appelant, c'est moins.
Je ne vois pas comment cela crée un problème SEC. Ce n'est pas comme si nous devions exécuter l'appel deux fois. Si nous avons toujours voulu faire la même chose lorsque la liste n'existe pas, nous pourrions peut-être pousser la gestion vers la fonction get-list plutôt que de demander à l'appelant de le faire, et donc mettre le code dans l'appelant serait une violation DRY. Mais nous ne voulons presque certainement pas toujours faire la même chose. Dans les fonctions où nous devons avoir la liste à traiter, une liste manquante est une erreur qui pourrait bien arrêter le traitement. Mais sur un écran d'édition, nous ne voulons certainement pas arrêter le traitement s'ils n'ont pas encore entré de données: nous voulons les laisser entrer des données. Ainsi, la gestion de "pas de liste" doit se faire au niveau de l'appelant d'une manière ou d'une autre. Et que nous le fassions avec un retour nul ou une fonction séparée ne fait aucune différence avec le principe plus large.
Bien sûr, si l'appelant ne vérifie pas null, le programme peut échouer avec une exception de pointeur nul. Mais s'il y a une fonction séparée "got any" et que l'appelant n'appelle pas cette fonction mais appelle aveuglément la fonction "get list", alors que se passe-t-il? S'il lance une exception ou échoue, eh bien, c'est à peu près la même chose que ce qui se passerait s'il retournait null et ne le vérifiait pas. S'il renvoie une liste vide, c'est tout simplement faux. Vous ne parvenez pas à faire la distinction entre "J'ai une liste avec zéro élément" et "Je n'ai pas de liste". C'est comme retourner zéro pour le prix lorsque l'utilisateur n'a entré aucun prix: c'est juste faux.
Je ne vois pas en quoi l'attachement d'un attribut supplémentaire à la collection aide. L'appelant doit encore le vérifier. Comment est-ce mieux que de vérifier null? Encore une fois, la pire chose qui puisse arriver est que le programmeur oublie de le vérifier et donne des résultats incorrects.
Une fonction qui renvoie null n'est pas une surprise si le programmeur est familier avec le concept de null signifiant "ne pas avoir de valeur", ce que je pense que tout programmeur compétent aurait dû entendre, qu'il pense que c'est une bonne idée ou non. Je pense qu'avoir une fonction séparée est plus un problème de "surprise". Si un programmeur n'est pas familier avec l'API, lorsqu'il exécute un test sans données, il découvre rapidement que parfois il récupère une valeur nulle. Mais comment pourrait-il découvrir l'existence d'une autre fonction à moins qu'il ne lui vienne à l'esprit qu'il pourrait y avoir une telle fonction et qu'il vérifie la documentation, et que la documentation soit complète et compréhensible? Je préfère de loin avoir une fonction qui me donne toujours une réponse significative, plutôt que deux fonctions que je dois connaître et me rappeler d'appeler les deux.
la source
Si une collection vide a un sens sémantique, c'est ce que je préfère retourner. Renvoyer une collection vide pour les
GetMessagesInMyInbox()
communications "vous n'avez vraiment aucun message dans votre boîte de réception", alors que le retournull
peut être utile pour indiquer que les données sont insuffisantes pour dire à quoi devrait ressembler la liste qui pourrait être retournée.la source
null
valeur ne semble certainement pas raisonnable, je pensais en termes plus généraux à celle-ci. Les exceptions sont également importantes pour communiquer le fait que quelque chose a mal tourné, mais si les "données insuffisantes" auxquelles il est fait référence sont parfaitement attendues, le fait de lever une exception entraînerait une mauvaise conception. Je pense plutôt à un scénario où c'est parfaitement possible et sans erreur du tout pour que la méthode ne puisse parfois pas calculer une réponse.Renvoyer null pourrait être plus efficace, car aucun nouvel objet n'est créé. Cependant, cela nécessiterait également souvent une
null
vérification (ou une gestion des exceptions).Sémantiquement,
null
et une liste vide ne signifie pas la même chose. Les différences sont subtiles et un choix peut être meilleur que l'autre dans des cas spécifiques.Quel que soit votre choix, documentez-le pour éviter toute confusion.
la source
On pourrait faire valoir que le raisonnement derrière Null Object Pattern est similaire à celui en faveur du retour de la collection vide.
la source
Dépend de la situation. S'il s'agit d'un cas spécial, retournez null. Si la fonction arrive juste à renvoyer une collection vide, alors évidemment, c'est ok. Cependant, renvoyer une collection vide en tant que cas spécial en raison de paramètres non valides ou d'autres raisons n'est PAS une bonne idée, car il masque une condition de cas spécial.
En fait, dans ce cas, je préfère généralement lever une exception pour m'assurer qu'elle n'est VRAIMENT pas ignorée :)
Dire que cela rend le code plus robuste (en renvoyant une collection vide) car ils n'ont pas à gérer la condition nulle est mauvais, car il masque simplement un problème qui devrait être géré par le code appelant.
la source
Je dirais que ce
null
n'est pas la même chose qu'une collection vide et vous devez choisir celle qui représente le mieux ce que vous retournez. Dans la plupart des cas, ilnull
n'y a rien (sauf en SQL). Une collection vide est quelque chose, quoique quelque chose de vide.Si vous devez choisir l'un ou l'autre, je dirais que vous devriez tendre vers une collection vide plutôt que null. Mais il y a des moments où une collection vide n'est pas la même chose qu'une valeur nulle.
la source
Pensez toujours en faveur de vos clients (qui utilisent votre API):
Le retour de 'null' pose très souvent des problèmes avec les clients qui ne gèrent pas correctement les vérifications nulles, ce qui provoque une NullPointerException pendant l'exécution. J'ai vu des cas où une telle vérification nulle manquante a forcé un problème de production prioritaire (un client utilisé pour chaque (...) sur une valeur nulle). Pendant le test, le problème ne s'est pas produit, car les données opérées étaient légèrement différentes.
la source
J'aime donner des explications ici, avec un exemple approprié.
Considérons un cas ici ..
Considérons ici les fonctions que j'utilise ..
Je peux facilement utiliser
ListCustomerAccount
etFindAll
au lieu de.,REMARQUE: Étant donné que AccountValue ne l'est pas
null
, la fonction Sum () ne retournera pasnull
. Par conséquent, je peux l'utiliser directement.la source
Nous avons eu cette discussion au sein de l'équipe de développement au travail il y a environ une semaine, et nous avons presque unanimement opté pour la collecte vide. Une personne a voulu retourner null pour la même raison que Mike spécifiée ci-dessus.
la source
Collection vide. Si vous utilisez C #, l'hypothèse est que la maximisation des ressources système n'est pas essentielle. Bien que moins efficace, le retour de Empty Collection est beaucoup plus pratique pour les programmeurs impliqués (pour la raison décrite ci-dessus).
la source
Le retour d'une collection vide est préférable dans la plupart des cas.
La raison en est la commodité de la mise en œuvre de l'appelant, un contrat cohérent et une mise en œuvre plus facile.
Si une méthode renvoie null pour indiquer un résultat vide, l'appelant doit implémenter un adaptateur de vérification null en plus de l'énumération. Ce code est ensuite dupliqué dans différents appelants, alors pourquoi ne pas mettre cet adaptateur dans la méthode afin qu'il puisse être réutilisé.
Une utilisation valide de null pour IEnumerable peut être une indication de résultat absent ou d'échec d'une opération, mais dans ce cas, d'autres techniques doivent être envisagées, telles que la levée d'une exception.
la source
Voir ici pour une tempête de merde élaborée sur
null
en général. Je ne suis pas d'accord avec la déclaration qui enundefined
est une autrenull
, mais elle vaut quand même la peine d'être lue. Et cela explique pourquoi vous devriez éviternull
du tout et pas seulement dans le cas que vous avez demandé. L'essence est, c'estnull
dans n'importe quelle langue un cas spécial. Vous devez penser ànull
une exception.undefined
est différent dans ce sens, ce code traitant d'un comportement indéfini n'est dans la plupart des cas qu'un bogue. C et la plupart des autres langues ont également un comportement non défini, mais la plupart d'entre elles n'ont pas d'identifiant pour cela dans la langue.la source
Du point de vue de la gestion de la complexité, objectif principal de l'ingénierie logicielle, nous voulons éviter de propager une complexité cyclomatique inutile aux clients d'une API. Renvoyer un null au client, c'est comme lui renvoyer le coût de complexité cyclomatique d'une autre branche de code.
(Cela correspond à une charge de test unitaire. Vous devez écrire un test pour le cas de retour nul, en plus du cas de retour de la collection vide.)
la source