Y a-t-il un moyen de vérifier si int est une énumération légale en C #?

J’ai lu quelques articles sur SO et il semble que la plupart des opérations de base manquent.

public enum LoggingLevel { Off = 0, Error = 1, Warning = 2, Info = 3, Debug = 4, Trace = 5 }; if (s == "LogLevel") { _log.LogLevel = (LoggingLevel)Convert.ToInt32("78"); _log.LogLevel = (LoggingLevel)Enum.Parse(typeof(LoggingLevel), "78"); _log.WriteDebug(_log.LogLevel.ToSsortingng()); } 

Cela ne fait pas exception, il est heureux de stocker 78 . Y a-t-il un moyen de valider une valeur entrant dans une énumération?

Découvrez Enum.IsDefined

Usage:

 if(Enum.IsDefined(typeof(MyEnum), value)) MyEnum a = (MyEnum)value; 

Voici l’exemple de cette page:

 using System; [Flags] public enum PetType { None = 0, Dog = 1, Cat = 2, Rodent = 4, Bird = 8, Reptile = 16, Other = 32 }; public class Example { public static void Main() { object value; // Call IsDefined with underlying integral value of member. value = 1; Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value)); // Call IsDefined with invalid underlying integral value. value = 64; Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value)); // Call IsDefined with ssortingng containing member name. value = "Rodent"; Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value)); // Call IsDefined with a variable of type PetType. value = PetType.Dog; Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value)); value = PetType.Dog | PetType.Cat; Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value)); // Call IsDefined with uppercase member name. value = "None"; Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value)); value = "NONE"; Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value)); // Call IsDefined with combined value value = PetType.Dog | PetType.Bird; Console.WriteLine("{0:D}: {1}", value, Enum.IsDefined(typeof(PetType), value)); value = value.ToSsortingng(); Console.WriteLine("{0:D}: {1}", value, Enum.IsDefined(typeof(PetType), value)); } } 

L’exemple affiche la sortie suivante:

 // 1: True // 64: False // Rodent: True // Dog: True // Dog, Cat: False // None: True // NONE: False // 9: False // Dog, Bird: False 

Les solutions ci-dessus ne traitent pas des situations [Flags] .

Ma solution ci-dessous peut avoir des problèmes de performance (je suis sûr que l’on pourrait optimiser de diverses manières) mais, essentiellement, cela prouvera toujours si une valeur enum est valide ou non .

Il repose sur trois hypothèses:

  • Les valeurs d’énumération en C # ne sont autorisées int , absolument rien d’autre
  • Les noms enum en C # doivent commencer par un caractère alphabétique
  • Aucun nom enum valide ne peut être avec un signe moins: -

L’appel de ToSsortingng() sur une énumération renvoie soit la valeur int si aucune énumération (indicateur ou non) n’est trouvée. Si une valeur enum autorisée est trouvée, elle affichera le nom de la correspondance.

Alors:

 [Flags] enum WithFlags { First = 1, Second = 2, Third = 4, Fourth = 8 } ((WithFlags)2).ToSsortingng() ==> "Second" ((WithFlags)(2 + 4)).ToSsortingng() ==> "Second, Third" ((WithFlags)20).ToSsortingng() ==> "20" 

En gardant ces deux règles à l’esprit, nous pouvons supposer que si le .NET Framework fait correctement son travail, tout appel à la méthode ToSsortingng() d’un enum valide aboutira à quelque chose ayant un caractère alphabétique comme premier caractère:

 public static bool IsValid(this TEnum enumValue) where TEnum : struct { var firstChar = enumValue.ToSsortingng()[0]; return (firstChar < '0' || firstChar > '9') && firstChar != '-'; } 

On pourrait l’appeler un “hack”, mais les avantages sont que, en s’appuyant sur la propre implémentation de Microsoft des normes Enum et C #, vous ne vous fiez pas à votre propre code ou contrôle potentiellement bogué. Dans des situations où les performances ne sont pas exceptionnellement critiques, cela permettra d’économiser beaucoup de déclarations de switch malveillantes ou d’autres vérifications!

modifier

Merci à @ChaseMedallion d’avoir souligné que mon implémentation initiale ne supportait pas les valeurs négatives. Cela a été corrigé et les tests fournis.

Et les tests pour le sauvegarder:

 [TestClass] public class EnumExtensionsTests { [Flags] enum WithFlags { First = 1, Second = 2, Third = 4, Fourth = 8 } enum WithoutFlags { First = 1, Second = 22, Third = 55, Fourth = 13, Fifth = 127 } enum WithoutNumbers { First, // 1 Second, // 2 Third, // 3 Fourth // 4 } enum WithoutFirstNumberAssigned { First = 7, Second, // 8 Third, // 9 Fourth // 10 } enum WithNagativeNumbers { First = -7, Second = -8, Third = -9, Fourth = -10 } [TestMethod] public void IsValidEnumTests() { Assert.IsTrue(((WithFlags)(1 | 4)).IsValid()); Assert.IsTrue(((WithFlags)(1 | 4)).IsValid()); Assert.IsTrue(((WithFlags)(1 | 4 | 2)).IsValid()); Assert.IsTrue(((WithFlags)(2)).IsValid()); Assert.IsTrue(((WithFlags)(3)).IsValid()); Assert.IsTrue(((WithFlags)(1 + 2 + 4 + 8)).IsValid()); Assert.IsFalse(((WithFlags)(16)).IsValid()); Assert.IsFalse(((WithFlags)(17)).IsValid()); Assert.IsFalse(((WithFlags)(18)).IsValid()); Assert.IsFalse(((WithFlags)(0)).IsValid()); Assert.IsTrue(((WithoutFlags)1).IsValid()); Assert.IsTrue(((WithoutFlags)22).IsValid()); Assert.IsTrue(((WithoutFlags)(53 | 6)).IsValid()); // Will end up being Third Assert.IsTrue(((WithoutFlags)(22 | 25 | 99)).IsValid()); // Will end up being Fifth Assert.IsTrue(((WithoutFlags)55).IsValid()); Assert.IsTrue(((WithoutFlags)127).IsValid()); Assert.IsFalse(((WithoutFlags)48).IsValid()); Assert.IsFalse(((WithoutFlags)50).IsValid()); Assert.IsFalse(((WithoutFlags)(1 | 22)).IsValid()); Assert.IsFalse(((WithoutFlags)(9 | 27 | 4)).IsValid()); Assert.IsTrue(((WithoutNumbers)0).IsValid()); Assert.IsTrue(((WithoutNumbers)1).IsValid()); Assert.IsTrue(((WithoutNumbers)2).IsValid()); Assert.IsTrue(((WithoutNumbers)3).IsValid()); Assert.IsTrue(((WithoutNumbers)(1 | 2)).IsValid()); // Will end up being Third Assert.IsTrue(((WithoutNumbers)(1 + 2)).IsValid()); // Will end up being Third Assert.IsFalse(((WithoutNumbers)4).IsValid()); Assert.IsFalse(((WithoutNumbers)5).IsValid()); Assert.IsFalse(((WithoutNumbers)25).IsValid()); Assert.IsFalse(((WithoutNumbers)(1 + 2 + 3)).IsValid()); Assert.IsTrue(((WithoutFirstNumberAssigned)7).IsValid()); Assert.IsTrue(((WithoutFirstNumberAssigned)8).IsValid()); Assert.IsTrue(((WithoutFirstNumberAssigned)9).IsValid()); Assert.IsTrue(((WithoutFirstNumberAssigned)10).IsValid()); Assert.IsFalse(((WithoutFirstNumberAssigned)11).IsValid()); Assert.IsFalse(((WithoutFirstNumberAssigned)6).IsValid()); Assert.IsFalse(((WithoutFirstNumberAssigned)(7 | 9)).IsValid()); Assert.IsFalse(((WithoutFirstNumberAssigned)(8 + 10)).IsValid()); Assert.IsTrue(((WithNagativeNumbers)(-7)).IsValid()); Assert.IsTrue(((WithNagativeNumbers)(-8)).IsValid()); Assert.IsTrue(((WithNagativeNumbers)(-9)).IsValid()); Assert.IsTrue(((WithNagativeNumbers)(-10)).IsValid()); Assert.IsFalse(((WithNagativeNumbers)(-11)).IsValid()); Assert.IsFalse(((WithNagativeNumbers)(7)).IsValid()); Assert.IsFalse(((WithNagativeNumbers)(8)).IsValid()); } } 

La réponse canonique serait Enum.IsDefined , mais c’est une: un peu lente si elle est utilisée dans une boucle serrée, et b: pas utile pour [Flags] énumérations de [Flags] .

Personnellement, je cesserais de m’inquiéter à ce sujet, et il suffit de switch appropriée en me rappelant:

  • s’il est correct de ne pas tout reconnaître (et de ne rien faire), alors n’ajoutez pas de default: par default: (ou default: vide default: expliquez pourquoi)
  • s’il y a un comportement par défaut sensible, mettez cela par default:
  • sinon, manipulez ceux que vous connaissez et lancez une exception pour le rest:

Ainsi:

 switch(someflag) { case TriBool.Yes: DoSomething(); break; case TriBool.No: DoSomethingElse(); break; case TriBool.FileNotFound: DoSomethingOther(); break; default: throw new ArgumentOutOfRangeException("someflag"); } 

Utilisation:

 Enum.IsDefined ( typeof ( Enum ), EnumValue ); 

Utilisez Enum.IsDefined .

Pour gérer les [Flags] vous pouvez également utiliser cette solution de C # Cookbook :

Tout d’abord, ajoutez une nouvelle valeur ALL à votre énumération:

 [Flags] enum Language { CSharp = 1, VBNET = 2, VB6 = 4, All = (CSharp | VBNET | VB6) } 

Ensuite, vérifiez si la valeur est dans ALL :

 public bool HandleFlagsEnum(Language language) { if ((language & Language.All) == language) { return (true); } else { return (false); } } 

Une façon de faire serait de compter sur le casting et l’énumération pour convertir les chaînes. Lorsque vous convertissez int en un type Enum, l’int est soit converti en une valeur enum correspondante, soit l’énum résultant ne contient que int en tant que valeur si la valeur enum n’est pas définie pour l’int.

 enum NetworkStatus{ Unknown=0, Active, Slow } int statusCode=2; NetworkStatus netStatus = (NetworkStatus) statusCode; bool isDefined = netStatus.ToSsortingng() != statusCode.ToSsortingng(); 

Non testé pour les cas de bord.