J'écris actuellement du code pour nconstrainedMelody qui a des méthodes génériques à faire avec les énumérations.
Maintenant, j'ai une classe statique avec un tas de méthodes qui sont uniquement destinées à être utilisées avec des énumérations "flags". Je ne peux pas ajouter cela comme contrainte ... il est donc possible qu'ils soient également appelés avec d'autres types d'énumération. Dans ce cas, je voudrais lever une exception, mais je ne sais pas laquelle lancer.
Juste pour rendre cela concret, si j'ai quelque chose comme ça:
// Returns a value with all bits set by any values
public static T GetBitMask<T>() where T : struct, IEnumConstraint
{
if (!IsFlags<T>()) // This method doesn't throw
{
throw new ???
}
// Normal work here
}
Quelle est la meilleure exception à lancer? ArgumentException
semble logique, mais c'est un argument de type plutôt qu'un argument normal, ce qui pourrait facilement confondre les choses. Dois-je introduire ma propre classe TypeArgumentException
? Utilisez InvalidOperationException
? NotSupportedException
? Rien d'autre?
Je préfère ne pas créer ma propre exception à moins que ce ne soit clairement la bonne chose à faire.
NotSupportedException
sonne comme il convient, mais la documentation indique clairement qu'il doit être utilisé dans un but différent. D'après les remarques de la classe MSDN:
Il existe des méthodes qui ne sont pas prises en charge dans la classe de base, avec l'espoir que ces méthodes seront implémentées à la place dans les classes dérivées. La classe dérivée peut implémenter uniquement un sous-ensemble des méthodes de la classe de base et lever NotSupportedException pour les méthodes non prises en charge.
Bien sûr, il y a une manière dont NotSupportedException
est évidemment assez bon, surtout compte tenu de son sens commun. Cela dit, je ne sais pas si c'est juste.
Étant donné le but de Mélodie sans contrainte ...
Il y a diverses choses utiles qui peuvent être faites avec des méthodes/classes génériques où il y a une contrainte de type "T: enum" ou "T: délégué" - mais malheureusement, celles-ci sont interdites en C #.
Cette bibliothèque d'utilitaires contourne les interdictions utilisant ildasm/ilasm ...
... il semble qu'un nouveau Exception
pourrait être en ordre malgré la charge de preuve élevée que nous devons justement rencontrer avant de créer un Exceptions
personnalisé. Quelque chose comme InvalidTypeParameterException
pourrait être utile dans toute la bibliothèque (ou peut-être pas - c'est sûrement un cas Edge, non?).
Les clients devront-ils pouvoir distinguer cela des exceptions BCL? Quand un client pourrait-il appeler cela accidentellement à l'aide d'un Vanilla enum
? Comment répondriez-vous aux questions posées par la réponse acceptée à Quels facteurs doivent être pris en considération lors de l'écriture d'une classe d'exception personnalisée?
J'éviterais NotSupportedException. Cette exception est utilisée dans le cadre où une méthode n'est pas implémentée et il existe une propriété indiquant que ce type d'opération n'est pas pris en charge. Ça ne va pas ici
Je pense que InvalidOperationException est l'exception la plus appropriée que vous pourriez lancer ici.
La programmation générique ne doit pas lancer à l'exécution pour les paramètres de type non valides. Il ne doit pas être compilé, vous devez avoir une application de temps de compilation. Je ne sais pas ce que contient IsFlag<T>()
, mais vous pouvez peut-être en faire une application de temps de compilation, comme essayer de créer un type qui n'est possible que de créer avec des 'flags'. Peut-être qu'une classe traits
peut vous aider.
Mise à jour
Si vous devez lancer, je voterais pour InvalidOperationException. Le raisonnement est que les types génériques ont paramètres et les erreurs liées aux paramètres (méthode) sont centrées autour de la hiérarchie ArgumentException. Cependant, la recommandation sur ArgumentException indique que
si l'échec n'implique pas les arguments eux-mêmes, alors InvalidOperationException doit être utilisée.
Il y a au moins un acte de foi là-dedans, que méthode les recommandations de paramètres doivent également être appliquées aux paramètres générique, mais il n'y a rien de mieux dans l'imho de la hiérarchie SystemException.
J'utiliserais NotSupportedException car c'est ce que vous dites. D'autres énumérations que celles spécifiques sont non prises en charge. Cela serait bien sûr indiqué plus clairement dans le message d'exception.
J'irais avec NotSupportedException
. Alors que ArgumentException
a l'air bien, c'est vraiment attendu lorsqu'un argument passé à une méthode est inacceptable. Un argument de type est une caractéristique déterminante de la méthode réelle que vous souhaitez appeler, pas un véritable "argument". InvalidOperationException
doit être levé lorsque l'opération que vous effectuez peut être valide dans certains cas, mais pour la situation particulière, elle est inacceptable.
NotSupportedException
est levée lorsqu'une opération n'est pas supportée par nature. Par exemple, lors de l'implémentation d'une interface où un membre particulier n'a pas de sens pour une classe. Cela ressemble à une situation similaire.
Apparemment, Microsoft utilise ArgumentException
pour cela, comme le montre l'exemple de Expression.Lambda <> , Enum.TryParse <> ou Marshal. GetDelegateForFunctionPointer <> dans la section Exceptions. Je n'ai trouvé aucun exemple indiquant le contraire non plus (malgré la recherche de la source de référence locale pour TDelegate
et TEnum
).
Donc, je pense qu'il est prudent de supposer qu'au moins dans le code Microsoft, il est courant d'utiliser ArgumentException
pour les arguments de type générique non valides en plus des variables de base. Étant donné que la description de l'exception dans docs ne fait pas de distinction entre ceux-ci, ce n'est pas trop étiré non plus.
Avec un peu de chance, il décidera définitivement de la question.
Je vais avec NotSupportedException.
Le lancement d'une exception sur mesure doit toujours être effectué dans tous les cas où cela est discutable. Une exception personnalisée fonctionnera toujours, quels que soient les besoins des utilisateurs d'API. Le développeur peut intercepter l'un ou l'autre type d'exception s'il ne s'en soucie pas, mais si le développeur a besoin d'une gestion spéciale, il sera SOL.
Je me méfie toujours d'écrire des exceptions personnalisées, uniquement parce qu'elles ne sont pas toujours clairement documentées et provoquent de la confusion si elles ne sont pas nommées correctement.
Dans ce cas, je lancerais une ArgumentException pour l'échec de vérification des drapeaux. Tout dépend vraiment de la préférence. Certaines normes de codage que j'ai vues vont jusqu'à définir les types d'exceptions à lever dans des scénarios comme celui-ci.
Si l'utilisateur essayait de transmettre quelque chose qui n'était pas une énumération, je lancerais une exception InvalidOperationException.
Éditer:
Les autres soulèvent un point intéressant selon lequel cela n'est pas pris en charge. Ma seule préoccupation avec une exception NotSupportedException est que ce sont généralement les exceptions qui sont levées lorsque de la "matière noire" a été introduite dans le système, ou pour le dire autrement: "Cette méthode doit entrer dans le système sur cette interface, mais nous avons gagné 'allumez-le jusqu'à la version 2.4 "
J'ai également vu NotSupportedExceptions être levé comme une exception de licence "vous exécutez la version gratuite de ce logiciel, cette fonction n'est pas prise en charge".
Modifier 2:
Un autre possible:
System.ComponentModel.InvalidEnumArgumentException
L'exception levée lors de l'utilisation d'arguments non valides qui sont des énumérateurs.
Que diriez-vous d'hériter de NotSupportedException. Bien que je convienne avec @Mehrdad que cela a le plus de sens, j'entends votre point de vue qu'il ne semble pas correspondre parfaitement. Héritez donc de NotSupportedException, et de cette façon, les personnes qui codent pour votre API peuvent toujours intercepter une NotSupportedException.
Je voterais également pour InvalidOperationException. J'ai fait un organigramme (incomplet) sur Directives de lancement d'exceptions .NET basé sur Framework Design Guidelines 2nd Ed. il y a quelque temps si quelqu'un est intéressé.