10
votes

Devrais-je vérifier si la clé particulière est présente dans le dictionnaire avant d'y accéder?

dois-je vérifier si la clé particulière est présente dans le dictionnaire si je suis sûr qu'il sera ajouté dans le dictionnaire au moment où j'atteigne le code pour y accéder?

Il y a deux façons d'accéder à la valeur dans le dictionnaire

  1. Vérification de la méthode contenant de la carte. Si cela retourne true, j'accède à l'utilisation de l'indexeur [clé] de l'objet de dictionnaire.

    ou

    1. trygetvalue qui retournera vrai ou faux ainsi que la valeur de retour via le paramètre Out.

      (2nd fonctionnera mieux que 1st si je veux obtenir de la valeur. Benchmark .)

      Cependant, si je suis sûr que la fonction qui accède à un dictionnaire global aura sûrement la clé, puis-je vérifier toujours à l'aide de trygetvalue ou sans vérifier, je devrais utiliser indexer [].

      ou je ne devrais jamais supposer cela et toujours vérifier?


0 commentaires

9 Réponses :


10
votes

Si le dictionnaire est global (statique / partagé), vous devez synchroniser l'accès à celui-ci (c'est important; sinon vous pouvez le corrompre).

Même si votre thread est uniquement Lecture forte> données, il doit respecter les verrous d'autres threads qui pourraient être modifiés. P>

Toutefois; Si vous êtes sûr que l'article est là, l'indexeur doit être bien: P>

Foo foo;
lock(syncLock) {
    if(!data.TryGetValue(key, out foo)) {
        foo = new Foo(key);
        data.Add(key, foo);
    }
}
// use foo...


4 commentaires

Nice, mais je ne pense pas que c'était la question? Je ne vois aucune référence à la concurrence? :)


"Dictionnaire mondial" - vient de me lancer dans un chemin donné. Si ma compréhension est incorrecte, l'OP peut simplement ignorer cette réponse ;-p


Pourquoi devons-nous prendre la serrure lorsque vous lisez des données du dictionnaire? Est-ce dû à l'expansion du dictionnaire / de reproche après une limite?


@Jadoon parce que ce n'est pas le fil sûr, même pour la lecture. Hashtable, en revanche, est sûre pour un nombre quelconque de lecteurs et au plus un écrivain, il est donc beaucoup plus facile d'utiliser simultanément



2
votes

Vérifiez toujours. Ne jamais dire jamais. Je suppose que votre application n'est pas si la performance essentielle que vous devrez enregistrer l'heure de vérification.

Conseil: Si vous décidez de ne pas vérifier, utilisez au moins debug.assert (dict.contasert (clé)); Cela ne sera compilé que lors du mode de débogage, votre version de version ne le contiendra pas. De cette façon, vous pouvez au moins avoir le chèque lors du débogage.

Toujours: Si possible, vérifiez-le: -)

Edit: Il y a eu des idées fausses ici. Par "TOUJOURS VÉRIFION" Je voulais non seulement utiliser un autre. Manipulation d'une exception correctement était également inclus dans cela. Donc, être plus précis: ne rien prendre pour acquis, attendez-vous à l'inattendu. Vérifiez par contenant de la carte contenant ou gérez l'exception potentielle, mais faites quelque chose au cas où l'élément n'est pas contenu.


9 commentaires

Je ne suis pas d'accord avec ça. Si la clé est censée être présente et n'est-ce pas, le bon comportement est de jeter une exception, oui? Et c'est exactement ce que l'indexeur fait - alors pourquoi ne pas utiliser ce comportement? De plus, je n'ai pas envie de changer de comportement entre les constructions de débogage et de libération ... Cela ressemble à une recette pour les problèmes.


Oui, le chèque de débogage n'était pas destiné à être la meilleure pratique. Mais c'est mieux que de ne pas vérifier du tout. Et jetant une exception si les données doivent être dans le dictionnaire sûr, c'est la bonne façon d'aller, mais ce n'est probablement pas une exception interne du dictionnaire, mais qui convient parfaitement au problème réel (e. G. InvalidOperationException).


Je suis d'accord avec Jon, vous ne vérifiez que lorsque cela peut être ou non, si vous êtes certain que cela devrait être là, le chemin correct est de permettre à l'exception d'être levé et de la gérer en conséquence.


La question initiale n'a rien dit de manipuler des excéquations. J'ai compris que c'est à propos de l'accès à l'index puis de l'espoir le meilleur. Par "TOUJOURS VÉRIFION", j'ai également inclus que les exceptions attrapantes et à agir Appropriatley. Je vais éditer le poste et affiner ma déclaration: Préparez-vous à l'inattendu.


Vous ne devriez certainement pas être attraper Exceptions - utilisez TryGetValue plutôt que d'accéder à un indexeur et d'attraper l'exception. Cependant, lorsque la clé devrait être présente, l'utilisation de l'indexeur peut donner une amélioration de la lisibilité sur des tests explicitement et de lancer une exception différente.


Tout ce que je dis, c'est faire quelque chose. Il voulait savoir s'il devait simplement accéder à l'index et espérer que Dieu l'aide. J'ai dit "non, vérifiez-le". Alors où est le problème? Je pense également que la méthode elle-même doit gérer la clé KeynotFoundException et Rethrow une exception personnalisée ou plus générale d'emballage générale. Et si la lisibilité était une raison pratique pour risquer l'instabilité, je dois avoir mal compris quelque chose.


Comment laisser l'exception propager la "instabilité de risque"? Catching KeyNotFoundException est définitivement une approche grotte que d'utiliser trygetvalue, mais à moins que je ne vraiment vouloir lancer un type d'exception personnalisé, je laisserais la claquée à la ligne de clés.


Cela dépend vraiment du code d'appel, mais je ne m'attendrais pas à ne pas avoir à attraper une phrase clés à un niveau supérieur à un niveau supérieur à peut-être une mise en œuvre de la collecte spécifique. Le laisser se propager dans mon code de haut niveau signifie éventuellement que la risques d'avoir une exception montrent à l'utilisateur qui aurait facilement pu empêcher de l'obtenir loin, ce qui est ce que je voulais dire en risquant l'instabilité.


BTW, mon exemple dans le commentaire précédent "Mise en œuvre de la collecte spécifique" est une mauvaise. Je veux juste dire n'importe quel code qui accède directement à une collection comme celle-ci. En outre, si les données sont si importantes pour une application telle qu'elle est dans cette question (puisqu'elle doit être là), je ne laisserai donc pas que l'abscence soit décrite par une phrase keynotfindexception, plus quelque chose comme une myreallylyimportantDatagissingException, ou du moins (comme je déjà dit) une invaliditéExceptionException.



18
votes

Utilisez l'indexeur si la touche est censée être présente - s'il n'est pas présent, il lancera une exception appropriée, qui est le bon comportement si l'absence de la clé indique un bogue.

S'il est valide pour la clé de ne pas présenter, utilisez trygetvalue et réagissez en conséquence.

(Appliquez également les conseils de Marc sur l'accès à un dictionnaire partagé en toute sécurité.)


2 commentaires

Une clé manquante est souvent une indication d'un autre problème. Si vous savez ce que le problème est et peut fournir un message plus utile, vous devriez envisager de jeter votre propre exception depuis le message d'accompagnement KeyNotFoundException est difficile à réduire à l'époque.


Il serait certainement utile que KeynotFoundException ait donné la clé aussi bien - mais autre que cela, juste la trace de la pile est normalement suffisante pour moi. Jusqu'où saisiriez-vous ceci: vérifier toutes les références nulelles possibles (pas seulement des arguments, mais des choses que vous attendez à l'intérieur de l'intérieur) pour la nullité et de jeter une exception personnalisée sur chacun de ceux-ci? Il y aura toujours des exceptions projetées par des bits du cadre en cas d'incohérence interne: si vous essayez d'anticiper chacun d'entre eux, le code finit par être davantage sur les cas d'erreur que de progresser.



0
votes

trygetvalue est le même code que l'indexation de la touche, à l'exception de l'ancien retourne une valeur par défaut (pour le paramètre ) où ce dernier jette une exception. Utilisez trygetvalue et vous obtiendrez des chèques cohérents avec absolument aucune perte de performance.

Edit: Comme le dit Jon, si vous savez qu'il aura toujours la clé, vous pouvez l'indexer et la laisser lancer l'exception appropriée. Toutefois, si vous pouvez fournir de meilleures informations de contexte en le jetant vous-même avec un message détaillé, cela serait préférable.


0 commentaires

0
votes

Il y a 2 trains de pensée à ce sujet d'un point de vue de la performance.

1) Évitez les exceptions dans la mesure du possible, car les exceptions sont chères - c'est-à-dire chèque avant d'essayer de récupérer une clé spécifique du dictionnaire, qu'il existe ou non. Une meilleure approche à mon avis s'il y a une chance équitable, cela pourrait ne pas exister. Cela empêcherait des exceptions assez communes.

2) Si vous êtes convaincu que l'article existera à 99% du temps, alors ne vérifiez pas que c'est l'existence avant d'y accéder. Les 1% des instants lorsqu'elles n'existaient pas, une exception sera lancée, mais vous avez économisé le temps pour les 99% d'autres temps en ne vérifiant pas.

Ce que je dis est, optimisez pour la majorité s'il y en a clairement. S'il y a un degré réel d'incertitude sur un élément existant, vérifiez avant de récupérer.


2 commentaires

Je ne pense pas que cela devrait vraiment être une performance du tout. Il devrait s'agir de l'exactitude: si la clé est attendue dans des situations correctes, c'est-à-dire un bogue pour la clé de ne pas y être, puis jetant une exception est la bonne approche de l'échec. Sinon, vous devez détecter cette situation sans en utilisant une exception - une manipulation des cas non exceptionnels avec des exceptions est une mauvaise idée, imo.


Je pense plus dans le scénario où il n'existant pas dans le dictionnaire ne devrait pas entraîner une défaillance par exemple. devrait plutôt utiliser une valeur par défaut ou doit l'ajouter si elle n'existe pas. Le cas où il devrait exister dans le dictionnaire, mais ce n'est pas un vrai bogue s'il n'existe pas - c'est-à-dire supposez que le dictionnaire soit une cache de certaines données d'une DB, disent que la DB est indisponible et que le cache ne manque pas de peupler, Mais vous ne voulez pas que cela provoque un échec dans le système. Difficile de traverser un exemple du monde réel, j'espère que je fais une sorte de sens!



0
votes

Si vous savez que le dictionnaire contient normalement la clé, vous n'avez pas à le vérifier avant d'y accéder.

Si quelque chose se tromperait et que le dictionnaire ne contient pas les éléments qu'il convient, vous pouvez laisser le dictionnaire jeter l'exception. La seule raison de la vérification de la clé d'abord serait si vous souhaitez prendre en charge cette situation de problème vous-même sans obtenir l'exception. Laisser le dictionnaire jeter l'exception et attraper qui est cependant un moyen parfaitement valide de manipuler la situation.


0 commentaires

0
votes

Je pense que Marc et Jon l'ont (comme d'habitude) jolie semée. Puisque vous mentionnez également des performances dans votre question, cela pourrait valoir la peine d'envisager comment vous verrouillez le dictionnaire.

Le verrouillage simple Serialise tout accès en lecture qui peut ne pas être souhaitable si la lecture est massivement fréquente et les écrit sont relativement peu nombreux. Dans ce cas à l'aide d'un ReaderWriterLockSlim pourrait être meilleur. L'inconvénient est que le code est un peu plus complexe et les écritures sont légèrement plus lentes.


0 commentaires

1
votes

Personnellement, je vérifierais que la clé est là, que vous soyez sûr que vous soyez sûr ou non, certains peuvent dire que ce chèque est superflu et que le dictionnaire organisera une exception que vous pouvez attraper, mais vous ne devez pas compter sur Cette exception, vous devriez vous vérifier, puis jeter votre propre exception, ce qui signifie quelque chose ou un objet de résultat avec un drapeau de réussite et une raison à l'intérieur ... Le mécanisme d'échec est vraiment en attendant.


0 commentaires

1
votes

La réponse est sûrement "tout dépend de la situation". Vous devez équilibrer le risque que la clé soit manquante du dictionnaire (faible pour les petits systèmes où il y a un accès limité aux données, où vous pouvez compter sur la commande, les choses sont effectuées, plus grandes des systèmes plus importants, plusieurs programmeurs accédant à la même chose. données, notamment avec accès en lecture / écriture / supprimer, où les threads sont impliqués et que la commande ne peut pas être garantie ou si les données proviennent de manière externe et la lecture peuvent échouer) avec l'impact du risque (systèmes critiques de sécurité, libérations commerciales ou systèmes qu'une entreprise compter comparé à quelque chose de fait pour le plaisir, pour un travail unique et / ou pour votre utilisation uniquement) et avec toutes les exigences de vitesse, de taille et de paresse.

Si je faisais un système pour contrôler la signalisation ferroviaire, je voudrais être en sécurité contre toutes les erreurs possibles et impossibles, et à l'abri des erreurs dans la manipulation des erreurs, etc. (Murphy's 2nd Law: "Qu'est-ce qui ne peut pas se tromper ira mal ».) Si je demande des trucs ensemble pour le plaisir, même si la taille et la vitesse ne sont pas un problème, je serai beaucoup plus détendu sur des choses comme celle-ci - je voudrais aller aux trucs amusants.

Bien sûr, il s'agit parfois des trucs amusants en soi.


0 commentaires