J'écris actuellement du code pour UnconstrainedMelody qui a des méthodes génériques à voir avec les enums.
Maintenant, j'ai une classe statique avec un tas de méthodes qui sont ne destinées qu'à ê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érations. Dans ce cas, j'aimerais lancer 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
Cela semble logique, mais c'est un argument de type plutôt qu'un argument normal, ce qui pourrait facilement semer la confusion. Dois-je présenter ma propre TypeArgumentException
classe? Utiliser InvalidOperationException
? NotSupportedException
? Rien d'autre?
Je plutôt pas créer ma propre exception pour ce à moins qu'il soit clairement la bonne chose à faire.
Réponses:
NotSupportedException
semble tout à fait convenable, mais la documentation indique clairement qu'il devrait être utilisé à des fins différentes. D'après les remarques de la classe MSDN:Bien sûr, il y a un moyen par lequel
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 la mélodie sans contrainte ...
... il semble qu'un nouveau
Exception
soit en ordre malgré le lourd fardeau de la preuve que nous devons à juste titre satisfaire avant de créer une personnalisationExceptions
. Quelque chose comme çaInvalidTypeParameterException
pourrait être utile dans toute la bibliothèque (ou peut-être pas - c'est sûrement un cas de pointe, non?).Les clients devront-ils être en mesure de distinguer cela des exceptions BCL? Quand un client pourrait-il accidentellement appeler cela en utilisant une vanille
enum
? Comment répondriez-vous aux questions posées par la réponse acceptée à Quels facteurs doivent être pris en compte lors de l'écriture d'une classe d'exceptions personnalisée?la source
InvalidOperationException
sont dégoûtantes, parce que "Foo demande à la collection Bar d'ajouter quelque chose qui existe déjà, donc Bar lance IOE" et "Foo demande à la collection Bar d'ajouter quelque chose, alors Bar appelle Boz qui lance IOE même si Bar ne s'y attend pas" lancera tous les deux le même type d'exception; le code qui s'attend à attraper le premier ne s'attendra pas à ce dernier. Cela étant dit ...Foo<T>
comme un "type général" etFoo<Bar>
comme un "type spécifique" dans ce contexte, même s'il n'y a pas de relation "d'héritage" entre eux.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 rentre pas ici
Je pense qu'InvalidOperationException est l'exception la plus appropriée que vous puissiez lancer ici.
la source
T
estenum
décoré avecFlags
, il serait valide de lancer NSE.StupidClrException
fait un nom amusant;)La programmation générique ne doit pas lancer lors de l'exécution pour les paramètres de type non valides. Il ne devrait pas compiler, vous devriez avoir une application de temps de compilation. Je ne sais pas quoi
IsFlag<T>()
contient, mais vous pouvez peut-être transformer cela en une application au moment de la compilation, comme essayer de créer un type qu'il n'est possible de créer qu'avec des «indicateurs». Peut-être qu'unetraits
classe peut vous aider.Mettre à jour
Si vous devez lancer, je voterais pour InvalidOperationException. Le raisonnement est que les types génériques ont des paramètres et que 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
Il y a au moins un acte de foi là-dedans, que les recommandations de paramètres de méthode doivent également être appliquées aux paramètres génériques , mais il n'y a rien de mieux dans la hiérarchie SystemException à mon humble avis.
la source
IsFlag<T>
détermine si l'énumération s'y est[FlagsAttribute]
appliquée et le CLR n'a pas de contraintes basées sur des attributs. Ce serait dans un monde parfait - ou il y aurait un autre moyen de le contraindre - mais dans ce cas, cela ne fonctionne tout simplement pas :(J'utiliserais NotSupportedException car c'est ce que vous dites. D'autres énumérations que celles spécifiques ne sont pas prises en charge . Cela serait bien entendu indiqué plus clairement dans le message d'exception.
la source
J'irais avec
NotSupportedException
. Bien que celaArgumentException
semble correct, il est vraiment attendu lorsqu'un argument passé à une méthode est inacceptable. Un argument de type est une caractéristique déterminante pour la méthode réelle que vous souhaitez appeler, pas un véritable «argument».InvalidOperationException
doit être lancée lorsque l'opération que vous effectuez peut être valide dans certains cas, mais pour la situation particulière, c'est inacceptable.NotSupportedException
est levée lorsqu'une opération n'est pas prise en charge 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.la source
Apparemment, Microsoft utilise
ArgumentException
pour cela, comme illustré sur l'exemple de Expression.Lambda <> , Enum.TryParse <> ou Marshal.GetDelegateForFunctionPointer <> dans la section Exceptions. Je n'ai pas trouvé d'exemple indiquant le contraire non plus (malgré la recherche d'une source de référence locale pourTDelegate
etTEnum
).Donc, je pense qu'il est prudent de supposer qu'au moins dans le code Microsoft, c'est une pratique courante à utiliser
ArgumentException
pour les arguments de type générique non valides en dehors des variables de base. Étant donné que la description de l'exception dans la documentation ne fait pas de distinction entre celles-ci, ce n'est pas non plus trop extensible.Espérons qu'il décide une fois pour toutes de la question.
la source
TypeArgumentException
deArgumentException
, simplement parce qu'un argument de type est pas régulier argument.Id aller avec NotSupportedExpcetion.
la source
Lancer une exception personnalisée doit toujours être fait dans tous les cas où cela est discutable. Une exception personnalisée fonctionnera toujours, quels que soient les besoins des utilisateurs de l'API. Le développeur pourrait attraper l'un ou l'autre type d'exception s'il ne s'en soucie pas, mais si le développeur a besoin d'un traitement spécial, il sera SOL.
la source
Que diriez-vous d'hériter de NotSupportedException. Bien que je sois d'accord avec @Mehrdad pour dire que cela a le plus de sens, j'entends votre remarque que cela ne semble pas correspondre parfaitement. Alors héritez de NotSupportedException, et de cette façon, les gens qui codent contre votre API peuvent toujours attraper une NotSupportedException.
la source
Je me méfie toujours d'écrire des exceptions personnalisées, uniquement au motif qu'elles ne sont pas toujours clairement documentées et qu'elles causent de la confusion si elles ne sont pas nommées correctement.
Dans ce cas, je lancerais une ArgumentException pour l'échec de la vérification des indicateurs. C'est vraiment une question de préférence. Certaines normes de codage que j'ai vues vont jusqu'à définir les types d'exceptions à lancer 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 sur le fait que cela n'est pas pris en charge. Ma seule préoccupation avec une NotSupportedException est que ce sont généralement les exceptions qui sont levées lorsque la "matière noire" a été introduite dans le système, ou pour le dire autrement, "Cette méthode doit aller dans le système sur cette interface, mais nous avons gagné ne l’activez pas avant 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:
L'exception levée lors de l'utilisation d'arguments non valides qui sont des énumérateurs.
la source
LicensingException
classe héritant deInvalidOperationException
.Je voterais également pour InvalidOperationException. J'ai fait un organigramme (incomplet) sur les directives de lancement d'exceptions .NET basées sur les Framework Design Guidelines 2nd Ed. il y a quelque temps si quelqu'un est intéressé.
la source