Question

Imaginer un objet, vous travaillez a une collection d'autres objets qui lui sont associés, par exemple, la collection de Contrôles sur une WinForm.Vous voulez vérifier un certain objet dans la collection, mais la collection n'a pas un Contains() la méthode.Il existe plusieurs façons de traiter cette question.

  • Mettre en place votre propre Contains() méthode par une boucle sur tous les éléments de la collection pour voir si l'un d'entre eux est ce que vous cherchez.Ce qui semble être la "meilleure pratique" approche.
  • Je suis récemment tombé sur un code où, au lieu d'une boucle, il y avait une tentative d'accès à l'objet à l'intérieur d'un rapport d'essai, comme suit:
try  
{  
    Object aObject = myCollection[myObject];  
}  
catch(Exception e)  
{  
    //if this is thrown, then the object doesn't exist in the collection
}

Ma question est comment les pauvres d'une programmation pratique considérez-vous la deuxième option, et pourquoi?Quelle est la performance de il par rapport à une boucle à travers la collection?

Était-ce utile?

La solution

Je dirais que c'est assez mauvaise pratique.Tandis que certaines personnes pourraient être heureux de dire que la boucle à travers la collection est moins efficace pour lancer une exception, il existe une surcharge de lancer une exception.Je voudrais aussi vous demander pourquoi vous utilisez une collection pour accéder à un élément par clé lorsque vous serait mieux adaptée à l'aide d'un dictionnaire ou d'une table de hachage.

Mon principal problème avec ce code, cependant, est que quel que soit le type de l'exception levée, vous êtes toujours à gauche avec le même résultat.

Par exemple, une exception peut être levée, car l'objet n'existe pas dans la collection, ou parce que la collection elle-même est nulle ou parce que vous ne pouvez pas jeter myCollect[myObject] pour aObject.

L'ensemble de ces exceptions seront gérés de la même manière, ce qui peut-être pas votre intention.

Ces sont un couple de nice articles sur quand et où il est normalement considéré comme acceptable pour lancer des exceptions:

J'aime particulièrement cette citation de l'article:

Il est important que les exceptions sont levée uniquement lorsqu'un imprévu ou d' une activité incorrecte se produit qui empêche une méthode à partir de la fin de sa normal fonction.La gestion des exceptions introduit une petite surcharge et abaisse la performance ne devrait donc pas être utilisé pour flux de programme normal au lieu de le traitement conditionnel.Il peut également être difficile de maintenir le code que il abuse de la gestion des exceptions dans ce façon.

Autres conseils

La règle générale est d'éviter d'utiliser les exceptions pour les flux de contrôle, à moins que les circonstances qui déclenchent l'exception sont "exceptionnelles" -- par exemple, extrêmement rare!

Si c'est quelque chose qui va se passer normalement et régulièrement, il certainement ne devrait pas être traitée comme une exception.

Les Exceptions sont très, très lent à cause de tous les coûts, donc il peut y avoir des raisons de performances ainsi, si cela arrivait assez souvent.

Si, lors de l'écriture de votre code, vous vous attendez à cet objet d'être dans la collection, et puis en cours d'exécution, vous trouvez que ce n'est pas le cas, je dirais que d'un cas exceptionnel, et il est bon d'utiliser une exception.

Toutefois, si vous êtes simplement en testant l'existence d'un objet, et vous trouvez qu'il n'est pas là, ce n'est pas exceptionnel.L'aide d'une exception dans ce cas n'est pas bon.

L'analyse des performances d'exécution dépend de la collection utilisée et de la méthode si la recherche.Qui ne devrait pas d'importance si.Ne laissez pas l'illusion de l'optimisation de vous tromper dans l'écriture du code source de confusion.

J'aurais penser plus à quel point je l'aime...mon instinct est, hein, pas tellement...

EDIT:Ryan Fox commentaires sur le cas exceptionnel est parfait, je suis d'accord

Comme pour les performances, il dépend de l'indexeur sur la collection.C# permet de remplacer l'indexeur de l'opérateur, donc si il est en train de faire une boucle for comme la méthode contains vous écrivez, alors il sera aussi lent (avec peut-être quelques nanosecondes plus lent en raison du try/catch...mais rien à craindre, à moins que le code lui-même est dans une énorme boucle).

Si l'indexation est O(1) (ou même O(log(n))...ou quoi que ce soit plus rapide que O(n)), alors le try/catch solution serait plus rapide bien sûr.

Aussi, je suis en supposant que l'indexeur est de lancer l'exception, si elle est de retour null, vous pouvez bien sûr vérifier la valeur null et ne pas utiliser le try/catch.

En général, l'utilisation de la gestion des exceptions pour le flux de programme et de la logique est une mauvaise pratique.Personnellement, je pense que la deuxième option est inacceptable utilisation d'exceptions.Étant donné les caractéristiques de langues couramment utilisé de nos jours (comme Linq et les lambdas en C# par exemple) il n'y a aucune raison de ne pas écrire votre propre méthode contains ().

Comme une dernière pensée, ces jours-ci la plupart des collections faire avoir une méthode contains déjà.Donc je pense que pour la plupart c'est un non-problème.

Les Exceptions doivent être exceptionnelles.

Quelque chose comme " La collecte est manquant, car la base de données a chuté en dessous c'est exceptionnel

Quelque chose comme "la clé n'est pas présente" est un comportement normal pour un dictionnaire.

Pour votre exemple de winforms de Contrôle de la collecte, de l' Controls la propriété dispose d'un ContainsKey la méthode, qui est ce que vous êtes supposé utiliser.

Il n'y a pas ContainsValue parce que lorsque vous traitez avec des dictionnaires/tables de hachage, il n'y a pas de voie rapide à court d'itérer sur l'ensemble de la collection, de vérifier si quelque chose est présent, si vous êtes vraiment découragé de le faire.

Quant à savoir POURQUOI les Exceptions doivent être exceptionnel, c'est environ 2 choses

  1. En indiquant ce que votre code est en train de faire.Vous voulez avoir votre code de correspondre à ce qu'il tente de réaliser, autant que possible, de sorte qu'il est lisible et maintenable.La gestion des exceptions ajoute un tas de trucs extra qui fait cet effet

  2. La brièveté de code.Vous souhaitez que votre code pour faire ce qu'il fait dans la manière la plus directe, de sorte qu'il est lisible et maintenable.Encore une fois, les trucs ajoutée par la gestion des exceptions est dans la manière de ce.

Jetez un oeil à ce blog à partir de Krzysztof: http://blogs.msdn.com/kcwalina/archive/2008/07/17/ExceptionalError.aspx

Les Exceptions doivent être utilisés pour communiquer les conditions d'erreur, mais ils ne devraient pas être utilisés comme la logique de contrôle (surtout quand il y a beaucoup plus simple de manière à déterminer une condition, telle que Contient).

Une partie de la question est que les exceptions, tandis que pas cher jeter sont coûteux à catch et tous exceptions sont pris à un moment donné.

Ce dernier est une solution acceptable.Bien que je n'hésiterais pas à accrocher à l'exception spécifique (ElementNotFound?) que la collecte jette dans ce cas.

Speedwise, il dépend la plupart des cas.Si vous avez plus de chances de trouver l'élément que de ne pas, à l'exception de la solution sera plus rapide.Si vous avez plus de chances d'échouer, ensuite cela dépend de la taille de la collection et de sa itération de la vitesse.De toute façon, vous voulez mesurer à l'encontre de l'usage normal de voir si c'est réellement un goulot de bouteille avant de s'inquiéter de la vitesse de ce genre.Aller pour la clarté de la première, et la deuxième solution est beaucoup plus clair que l'ancien.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top