Question

Ceci est lié aux conventions utilisées dans C #.

I ai une méthode qui a deux paramètres (coordonnées X et Y). Ces coordonnées représentent la position à laquelle une « tuile » peut résider. Si une tuile réside à ces coordonnées, la méthode renvoie son numéro. Si aucune tuile réside à ces coordonnées, je me demande comment la méthode doit se comporter.

Je vois trois options:

  1. Utiliser des exceptions. Je peux soulever une exception à chaque fois que la méthode ne trouve aucune tuile. Cependant, cette situation n'est pas rare, cette option est la pire.
  2. Faites-la à l'ancienne C ++ aller et retour -1 s'il n'y a pas la tuile.
  3. le nombre de tuiles un paramètre de référence et modifier le type de retour de la méthode booléenne pour indiquer s'il y a une tuile ou non. Mais cela semble un peu compliqué pour moi.

Alors, que dois-je faire?

Était-ce utile?

La solution

Retour -1.

Ce n'est pas seulement une convention C ++, il est aussi courant dans le .NET Framework - par exemple des méthodes telles que String.indexOf ou propriétés comme SelectedIndex des contrôles qui représentent des listes.

EDIT

Juste pour élaborer, des trois options de votre question (Exception, retour -1, paramètre out), le retour -1 est le chemin à parcourir. Des exceptions sont des situations exceptionnelles, et les lignes directrices de codage Microsoft recommande d'éviter des paramètres si possible.

À mon avis retour -1 (à condition que ça va toujours être une valeur non valide), renvoyant un int nullable ou retourner un objet de carreaux sont toutes les solutions acceptables, et vous devez choisir celui qui est le plus compatible avec le reste de votre application . Je ne peux pas imaginer un développeur aurait la moindre difficulté avec les éléments suivants:

int tileNumber = GetTile(x,y);
if  (tileNumber != -1)
{
   ... use tileNumber ...
}


int? result = GetTile(x,y);
if (result.HasValue)
{
    int tileNumber = result.Value; 
   ... use tileNumber ...
}


Tile tile = GetTile(x,y);
if (tile != null)
{
   ... use tile ...
}

Je ne suis pas sûr que je comprends le commentaire de Peter Ruderman sur l'utilisation d'un int étant « beaucoup plus efficace que de retourner un type nullable ». Je l'aurais pensé toute différence serait négligeable.

Autres conseils

Vous pouvez retourner null, et vérifier cela sur le code d'appel.

Bien sûr, vous auriez à utiliser un type Nullable:

int? i = YourMethodHere(x, y);

Les exceptions sont des cas exceptionnels, donc en utilisant des exceptions sur une connus et devrait situation d'erreur est "mauvais". Vous êtes également plus probable, maintenant, d'avoir partout essayages prises pour gérer cette erreur précisément parce que vous attendez cette situation d'erreur se produise.

Rendre votre valeur de retour d'un paramètre est acceptable si votre seule condition d'erreur (par exemple -1) est une valeur confusable réelle. Si vous pouvez avoir un numéro de tuile négatif, c'est une meilleure façon d'aller.

int nullable est une alternative possible à un paramètre de référence, mais vous créez des objets avec ce que si une « erreur » est une routine, ils vous pouvez être faire plus de travail ainsi qu'un paramètre de référence. Comme l'a souligné Roman dans un commentaire ailleurs, vous aurez C # par rapport à des problèmes de VB avec le type nullable introduit trop tard pour VB pour fournir agréable sucre syntaxique comme C # a.

Si vos tuiles ne peuvent être alors non négatif retour -1 est une façon acceptable et traditionnelle pour indiquer une erreur. Il serait également le moins cher en termes de performance et de la mémoire.


Autre chose à considérer est l'auto-documentation. -1 et une en utilisant exception sont convention: il vous faudrait écrire la documentation pour vous assurer que le développeur est au courant. L'utilisation d'un retour de int? ou un paramètre de référence serait mieux se auto-décrire et ne serait pas besoin documentation pour un développeur de savoir comment gérer la situation d'erreur. Bien sûr :) vous devriez toujours écrire la documentation, tout comme la façon dont vous devez utiliser la soie dentaire tous les jours.

Utilisez une valeur de retour annulable.

int? GetTile(int x, int y) {
   if (...)
      return SomeValue;
   else
      return null;
}

est la plus claire solution.

Si votre méthode a accès aux objets sous-jacents de tuiles, une autre possibilité serait de renvoyer l'objet carreau lui-même, ou null s'il n'y a pas la tuile.

Je vais avec l'option 2. Vous avez raison, lancer une exception dans ce cas commun peut être mauvais pour la performance, et en utilisant un paramètre et en retournant un vrai ou faux est utile, mais çela à lire.

De plus, pensez à la méthode string.IndexOf(). Si rien ne se trouve, il renvoie -1. Je suis cet exemple.

Vous pouvez revenir -1, car c'est une approche C # assez commun. Cependant, il pourrait être préférable de revenir en fait la tuile qui a été cliqué, et dans le cas où aucune tuile a été cliqué, renvoyer une référence à un singleton exemple NullTile. L'avantage de ce faire de cette façon est que vous donner un sens concret à chaque valeur renvoyée, plutôt que ce soit juste un chiffre qui n'a pas de signification intrinsèque au-delà de sa valeur numérique. Un type « NullTile » est très spécifique quant à sa signification, ce qui laisse peu de doute pour d'autres lecteurs de votre code.

Les meilleures options pour retourner un booléen aussi bien ou return null.

par exemple.

bool TryGetTile(int x, int y, out int tile);

ou

int? GetTile(int x, int y);

Il y a plusieurs raisons de préférer le modèle « TryGetValue ». D'une part, elle retourne un booléen, si le code client est très en avant, par exemple droit: si (TryGetValue (hors someVal)) {/ * du code * /}. Comparez cela à un code client qui nécessite des comparaisons de valeur sentinelle codées en dur (à -1, 0, null, attrapant un ensemble particulier d'exceptions, etc.) « Les nombres magiques » récolte rapidement avec ces conceptions et d'affacturage sur le couplage étroit devient une corvée.

Lorsque des valeurs sentinelles, nulles ou exceptions devraient il est absolument essentiel que vous consultez la documentation sur laquelle le mécanisme est utilisé. Si la documentation n'existe pas ou est pas accessible, un scénario commun, alors vous devez déduire la base d'autres éléments de preuve, si vous faites le mauvais choix que vous êtes vous-même tout simplement une exception référence nulle ou autres mauvais défauts. Considérant que, le motif TryGetValue () est assez proche de autodocumenté par son nom et signature de la méthode seule.

J'ai mon propre avis sur la question que vous avez posée, mais il est dit ci-dessus et j'ai voté en conséquence.

Quant à la question que vous n'avez pas demandé, ou au moins comme une extension à toutes les réponses ci-dessus: je serais sûr de garder la solution à des situations similaires cohérentes dans l'application. En d'autres termes, quelle que soit la réponse que vous installer sur, gardez-même dans l'application.

Si la méthode fait partie d'une bibliothèque de bas niveau, votre conception standard .NET probablement dicte que vous jetez des exceptions de votre méthode.

Voici comment le framework .NET fonctionne en général. Vos interlocuteurs de haut niveau devraient prendre vos exceptions.

Cependant, comme vous semblez le faire à partir d'un thread d'interface utilisateur, ce qui a des répercussions sur la performance puisque vous réagissez aux événements de l'interface utilisateur - Je fais ce que Jay Riggs déjà suggéré, return null, et assurez-vous que vos appelants vérifient une valeur de retour null .

Je brisaient en deux méthodes. Vous avez quelque chose comme CheckTileExists(x,y) et GetTile(x,y). La première renvoie un booléen qui indique si oui ou non il y a une tuile aux coordonnées données. La deuxième méthode est essentiellement celle que vous parlez dans votre message original, sauf qu'il doit lancer une exception lorsque donné les coordonnées invalides (car qui indique que l'appelant n'a pas premier appel CheckTileExists(), il est donc légitime d'une situation exceptionnelle. Pour la souci de vitesse, vous voudrez probablement ces deux méthodes pour partager un cache, de sorte que dans le cas où ils sont appelés l'un après l'autre, les frais généraux sur la fonction GetTile() serait négligeable. Je ne sais pas si vous avez déjà un objet approprié pour mettre ces méthodes ou si peut-être vous devriez les faire deux méthodes sur une nouvelle classe. à mon humble avis, la peine de la performance de cette approche est négligeable et l'augmentation de la clarté du code dépasse de loin il.

Est-il possible que vous avez créé (ou pourrait créer) un objet Tile qui est référencé aux coordonnées? Si oui, vous pouvez retourner une référence à cette tuile ou null s'il n'y a pas la tuile aux coordonnées données:

public Tile GetTile(int x, int y) {
    if (!TileExists(x, y)) 
        return null;
    // ... tile lookup here...
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top