Mes énumérations peuvent-elles avoir des noms amicaux?

J’ai la enum suivante

 public enum myEnum { ThisNameWorks, This Name doesn't work Neither.does.this; } 

N’est-il pas possible d’avoir des enum s avec des “noms amis”?

Les noms de valeur enum doivent suivre les mêmes règles de nommage que tous les identificateurs en C #, par conséquent, seul le prénom est correct.

Vous pouvez utiliser l’atsortingbut Description , comme l’a suggéré Yuriy. La méthode d’extension suivante facilite l’obtention de la description pour une valeur donnée de l’énumération:

  public static ssortingng GetDescription(this Enum value) { Type type = value.GetType(); ssortingng name = Enum.GetName(type, value); if (name != null) { FieldInfo field = type.GetField(name); if (field != null) { DescriptionAtsortingbute attr = Atsortingbute.GetCustomAtsortingbute(field, typeof(DescriptionAtsortingbute)) as DescriptionAtsortingbute; if (attr != null) { return attr.Description; } } } return null; } 

Vous pouvez l’utiliser comme ça:

 public enum MyEnum { [Description("Description for Foo")] Foo, [Description("Description for Bar")] Bar } MyEnum x = MyEnum.Foo; ssortingng description = x.GetDescription(); 

Si vous avez la énumération suivante:

 public enum MyEnum { First, Second, Third } 

Vous pouvez déclarer des méthodes d’extension pour MyEnum (comme vous pouvez le faire pour tout autre type). Je viens de fouetter ça:

 namespace Extension { public static class ExtensionMethods { public static ssortingng EnumValue(this MyEnum e) { switch (e) { case MyEnum.First: return "First Friendly Value"; case MyEnum.Second: return "Second Friendly Value"; case MyEnum.Third: return "Third Friendly Value"; } return "Horrible Failure!!"; } } } 

Avec cette méthode d’extension, les éléments suivants sont désormais légaux:

 Console.WriteLine(MyEnum.First.EnumValue()); 

J’espère que cela t’aides!!

Non, mais vous pouvez utiliser l’ outil DescriptionAtsortingbute pour accomplir ce que vous recherchez.

Vous pouvez utiliser l’atsortingbut de description pour obtenir ce nom convivial. Vous pouvez utiliser le code ci-dessous:

 ///  /// Very good method to Override ToSsortingng on Enums /// Case : Suppose your enum value is EncryptionProviderType and you want /// enumVar.Tossortingng() to retrun "Encryption Provider Type" then you should use this method. /// Prerequirejsite : All enum members should be applied with atsortingbute [Description("Ssortingng to be returned by Tossortingng()")] /// Example : /// enum ExampleEnum /// { /// [Description("One is one")] /// ValueOne = 1, /// [Description("Two is two")] /// ValueTow = 2 /// } /// /// in your class /// ExampleEnum enumVar = ExampleEnum.ValueOne ; /// Console.WriteLine(ToSsortingngEnums(enumVar)); ///  ///  ///  public static ssortingng ToSsortingngEnums(Enum en) { Type type = en.GetType(); MemberInfo[] memInfo = type.GetMember(en.ToSsortingng()); if (memInfo != null && memInfo.Length > 0) { object[] attrs = memInfo[0].GetCustomAtsortingbutes(typeof(DescriptionAtsortingbute), false); if (attrs != null && attrs.Length > 0) return ((DescriptionAtsortingbute)attrs[0]).Description; } return en.ToSsortingng(); } 

Un problème avec cette astuce est que l’atsortingbut de description ne peut pas être localisé. Je fais comme une technique de Sacha Barber où il crée sa propre version de l’atsortingbut Description qui reprendrait les valeurs du gestionnaire de ressources correspondant.

http://www.codeproject.com/KB/WPF/FriendlyEnums.aspx

Bien que l’article concerne un problème généralement rencontré par les développeurs WPF lors de la liaison aux énumérations, vous pouvez accéder directement à la partie où il crée LocalizableDescriptionAtsortingbute.

Certaines excellentes solutions ont déjà été publiées. Lorsque j’ai rencontré ce problème, je voulais aller dans les deux sens: convertir un enum en une description et convertir une chaîne correspondant à une description en une énumération.

J’ai deux variantes, lente et rapide. Les deux convertissent d’énum en chaîne et de chaîne en enum. Mon problème est que j’ai des énumérations comme celle-ci, où certains éléments ont besoin d’atsortingbuts et d’autres pas. Je ne veux pas mettre d’atsortingbuts sur des éléments qui n’en ont pas besoin. J’ai environ une centaine de ces totaux actuellement:

 public enum POS { CC, // Coordinating conjunction CD, // Cardinal Number DT, // Determiner EX, // Existential there FW, // Foreign Word IN, // Preposision or subordinating conjunction JJ, // Adjective [System.ComponentModel.Description("WP$")] WPDollar, //$ Possessive wh-pronoun WRB, // Wh-adverb [System.ComponentModel.Description("#")] Hash, [System.ComponentModel.Description("$")] Dollar, [System.ComponentModel.Description("''")] DoubleTick, [System.ComponentModel.Description("(")] LeftParenth, [System.ComponentModel.Description(")")] RightParenth, [System.ComponentModel.Description(",")] Comma, [System.ComponentModel.Description(".")] Period, [System.ComponentModel.Description(":")] Colon, [System.ComponentModel.Description("``")] DoubleBackTick, }; 

La première méthode pour y faire face est lente et repose sur des suggestions que j’ai vues ici et autour du net. C’est lent parce que nous réfléchissons à chaque conversion:

 using System; using System.Collections.Generic; namespace CustomExtensions { ///  /// uses extension methods to convert enums with hypens in their names to underscore and other variants public static class EnumExtensions { ///  /// Gets the description ssortingng, if available. Otherwise returns the name of the enum field /// LthWrapper.POS.Dollar.GetSsortingng() yields "$", an impossible control character for enums ///  ///  ///  public static ssortingng GetSsortingngSlow(this Enum value) { Type type = value.GetType(); ssortingng name = Enum.GetName(type, value); if (name != null) { System.Reflection.FieldInfo field = type.GetField(name); if (field != null) { System.ComponentModel.DescriptionAtsortingbute attr = Atsortingbute.GetCustomAtsortingbute(field, typeof(System.ComponentModel.DescriptionAtsortingbute)) as System.ComponentModel.DescriptionAtsortingbute; if (attr != null) { //return the description if we have it name = attr.Description; } } } return name; } ///  /// Converts a ssortingng to an enum field using the ssortingng first; if that fails, sortinges to find a description /// atsortingbute that matches. /// "$".ToEnum() yields POS.Dollar ///  ///  ///  ///  public static T ToEnumSlow(this ssortingng value) //, T defaultValue) { T theEnum = default(T); Type enumType = typeof(T); //check and see if the value is a non atsortingbute value try { theEnum = (T)Enum.Parse(enumType, value); } catch (System.ArgumentException e) { bool found = false; foreach (T enumValue in Enum.GetValues(enumType)) { System.Reflection.FieldInfo field = enumType.GetField(enumValue.ToSsortingng()); System.ComponentModel.DescriptionAtsortingbute attr = Atsortingbute.GetCustomAtsortingbute(field, typeof(System.ComponentModel.DescriptionAtsortingbute)) as System.ComponentModel.DescriptionAtsortingbute; if (attr != null && attr.Description.Equals(value)) { theEnum = enumValue; found = true; break; } } if( !found ) throw new ArgumentException("Cannot convert " + value + " to " + enumType.ToSsortingng()); } return theEnum; } } } 

Le problème est que vous faites de la reflection à chaque fois. Je n’ai pas mesuré l’impact de la performance, mais cela semble alarmant. Pire, nous calculons ces conversions coûteuses de manière répétée, sans les mettre en cache.

Au lieu de cela, nous pouvons utiliser un constructeur statique pour remplir certains dictionnaires avec ces informations de conversion, puis rechercher ces informations lorsque cela est nécessaire. Les classes apparemment statiques (requirejses pour les méthodes d’extension) peuvent avoir des constructeurs et des champs 🙂

 using System; using System.Collections.Generic; namespace CustomExtensions { ///  /// uses extension methods to convert enums with hypens in their names to underscore and other variants /// I'm not sure this is a good idea. While it makes that section of the code much much nicer to maintain, it /// also incurs a performance hit via reflection. To circumvent this, I've added a dictionary so all the lookup can be done once at /// load time. It requires that all enums involved in this extension are in this assembly. ///  public static class EnumExtensions { //To avoid collisions, every Enum type has its own hash table private static readonly Dictionary> enumToSsortingngDictionary = new Dictionary>(); private static readonly Dictionary> ssortingngToEnumDictionary = new Dictionary>(); static EnumExtensions() { //let's collect the enums we care about List enumTypeList = new List(); //probe this assembly for all enums System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); Type[] exportedTypes = assembly.GetExportedTypes(); foreach (Type type in exportedTypes) { if (type.IsEnum) enumTypeList.Add(type); } //for each enum in our list, populate the appropriate dictionaries foreach (Type type in enumTypeList) { //add dictionaries for this type EnumExtensions.enumToSsortingngDictionary.Add(type, new Dictionary() ); EnumExtensions.ssortingngToEnumDictionary.Add(type, new Dictionary() ); Array values = Enum.GetValues(type); //its ok to manipulate 'value' as object, since when we convert we're given the type to cast to foreach (object value in values) { System.Reflection.FieldInfo fieldInfo = type.GetField(value.ToSsortingng()); //check for an atsortingbute System.ComponentModel.DescriptionAtsortingbute atsortingbute = Atsortingbute.GetCustomAtsortingbute(fieldInfo, typeof(System.ComponentModel.DescriptionAtsortingbute)) as System.ComponentModel.DescriptionAtsortingbute; //populate our dictionaries if (atsortingbute != null) { EnumExtensions.enumToSsortingngDictionary[type].Add(value, atsortingbute.Description); EnumExtensions.ssortingngToEnumDictionary[type].Add(atsortingbute.Description, value); } else { EnumExtensions.enumToSsortingngDictionary[type].Add(value, value.ToSsortingng()); EnumExtensions.ssortingngToEnumDictionary[type].Add(value.ToSsortingng(), value); } } } } public static ssortingng GetSsortingng(this Enum value) { Type type = value.GetType(); ssortingng aSsortingng = EnumExtensions.enumToSsortingngDictionary[type][value]; return aSsortingng; } public static T ToEnum(this ssortingng value) { Type type = typeof(T); T theEnum = (T)EnumExtensions.ssortingngToEnumDictionary[type][value]; return theEnum; } } } 

Regardez comme les méthodes de conversion sont maintenant très serrées. Le seul défaut auquel je peux penser est que cela nécessite que toutes les énumérations converties soient dans l’assemblée actuelle. De plus, je ne me préoccupe que des chiffres exportés, mais vous pouvez changer cela si vous le souhaitez.

Voici comment appeler les méthodes

  ssortingng x = LthWrapper.POS.Dollar.GetSsortingng(); LthWrapper.POS y = "PRP$".ToEnum(); 
 public enum myEnum { ThisNameWorks, This_Name_can_be_used_instead, } 

Après avoir lu de nombreuses ressources sur ce sujet, y compris StackOverFlow, je trouve que toutes les solutions ne fonctionnent pas correctement. Voici notre tentative pour résoudre ce problème.

Fondamentalement, nous prenons le nom convivial d’un Enum d’un DescriptionAtsortingbute s’il existe.
Si ce n’est pas le cas, nous utilisons RegEx pour déterminer les mots du nom Enum et append des espaces.

Dans la prochaine version, nous utiliserons un autre atsortingbut pour indiquer si nous pouvons / devons prendre le nom convivial d’un fichier de ressources localisable.

Voici les cas de test. S’il vous plaît signaler si vous avez un autre cas de test qui ne réussit pas.

 public static class EnumHelper { public static ssortingng ToDescription(Enum value) { if (value == null) { return ssortingng.Empty; } if (!Enum.IsDefined(value.GetType(), value)) { return ssortingng.Empty; } FieldInfo fieldInfo = value.GetType().GetField(value.ToSsortingng()); if (fieldInfo != null) { DescriptionAtsortingbute[] atsortingbutes = fieldInfo.GetCustomAtsortingbutes(typeof (DescriptionAtsortingbute), false) as DescriptionAtsortingbute[]; if (atsortingbutes != null && atsortingbutes.Length > 0) { return atsortingbutes[0].Description; } } return SsortingngHelper.ToFriendlyName(value.ToSsortingng()); } } public static class SsortingngHelper { public static bool IsNullOrWhiteSpace(ssortingng value) { return value == null || ssortingng.IsNullOrEmpty(value.Trim()); } public static ssortingng ToFriendlyName(ssortingng value) { if (value == null) return ssortingng.Empty; if (value.Trim().Length == 0) return ssortingng.Empty; ssortingng result = value; result = ssortingng.Concat(result.Subssortingng(0, 1).ToUpperInvariant(), result.Subssortingng(1, result.Length - 1)); const ssortingng pattern = @"([AZ]+(?![az])|\d+|[AZ][az]+|(?![AZ])[az]+)+"; List words = new List(); Match match = Regex.Match(result, pattern); if (match.Success) { Group group = match.Groups[1]; foreach (Capture capture in group.Captures) { words.Add(capture.Value); } } return ssortingng.Join(" ", words.ToArray()); } } [TestMethod] public void TestFriendlyName() { ssortingng[][] cases = { new ssortingng[] {null, ssortingng.Empty}, new ssortingng[] {ssortingng.Empty, ssortingng.Empty}, new ssortingng[] {" ", ssortingng.Empty}, new ssortingng[] {"A", "A"}, new ssortingng[] {"z", "Z"}, new ssortingng[] {"Pascal", "Pascal"}, new ssortingng[] {"camel", "Camel"}, new ssortingng[] {"PascalCase", "Pascal Case"}, new ssortingng[] {"ABCPascal", "ABC Pascal"}, new ssortingng[] {"PascalABC", "Pascal ABC"}, new ssortingng[] {"Pascal123", "Pascal 123"}, new ssortingng[] {"Pascal123ABC", "Pascal 123 ABC"}, new ssortingng[] {"PascalABC123", "Pascal ABC 123"}, new ssortingng[] {"123Pascal", "123 Pascal"}, new ssortingng[] {"123ABCPascal", "123 ABC Pascal"}, new ssortingng[] {"ABC123Pascal", "ABC 123 Pascal"}, new ssortingng[] {"camelCase", "Camel Case"}, new ssortingng[] {"camelABC", "Camel ABC"}, new ssortingng[] {"camel123", "Camel 123"}, }; foreach (ssortingng[] givens in cases) { ssortingng input = givens[0]; ssortingng expected = givens[1]; ssortingng output = SsortingngHelper.ToFriendlyName(input); Assert.AreEqual(expected, output); } } } 

Ils suivent les mêmes règles de nommage que les noms de variables. Par conséquent, ils ne doivent pas contenir d’espaces.

De plus, ce que vous proposez serait une très mauvaise pratique de toute façon.

Les noms enum vivent sous les mêmes règles que les noms de variables normaux, c’est-à-dire qu’aucun espace ou point n’est placé au milieu des noms.

C’est une idée terrible, mais ça marche.

  public enum myEnum { ThisNameWorks, ThisNameDoesntWork149141331,// This Name doesn't work NeitherDoesThis1849204824// Neither.does.this; } class Program { private static unsafe void ChangeSsortingng(ssortingng original, ssortingng replacement) { if (original.Length < replacement.Length) throw new ArgumentException(); fixed (char* pDst = original) fixed (char* pSrc = replacement) { // Update the length of the original string int* lenPtr = (int*)pDst; lenPtr[-1] = replacement.Length; // Copy the characters for (int i = 0; i < replacement.Length; i++) pDst[i] = pSrc[i]; } } public static unsafe void Initialize() { ChangeString(myEnum.ThisNameDoesntWork149141331.ToString(), "This Name doesn't work"); ChangeString(myEnum.NeitherDoesThis1849204824.ToString(), "Neither.does.this"); } static void Main(string[] args) { Console.WriteLine(myEnum.ThisNameWorks); Console.WriteLine(myEnum.ThisNameDoesntWork149141331); Console.WriteLine(myEnum.NeitherDoesThis1849204824); Initialize(); Console.WriteLine(myEnum.ThisNameWorks); Console.WriteLine(myEnum.ThisNameDoesntWork149141331); Console.WriteLine(myEnum.NeitherDoesThis1849204824); } 

Exigences

  1. Vos noms enum doivent avoir le même nombre de caractères ou plus que la chaîne que vous souhaitez voir apparaître.

  2. Vos noms d'énumération ne doivent pas être répétés n'importe où, juste au cas où l'internement de chaînes nuirait aux choses

Pourquoi c'est une mauvaise idée (quelques raisons)

  1. Vos noms de énumération deviennent laids des exigences

  2. Il s'appuie sur l'appel rapide de la méthode d'initialisation

  3. Pointeurs dangereux

  4. Si le format interne de la chaîne change, par exemple si le champ de longueur est déplacé, vous êtes vissé

  5. Si Enum.ToSsortingng () est modifié pour qu'il ne retourne qu'une copie, vous êtes vissé

  6. Raymond Chen se plaindra de votre utilisation des fonctionnalités non documentées, et de la faute de l'équipe de CLR qui n'a pas réussi à optimiser le temps d'exécution de 50%, lors de sa prochaine semaine .NET.

Je suppose que vous voulez montrer vos valeurs enum à l’utilisateur donc vous voulez qu’ils aient un nom convivial. Voici ma suggestion: Utilisez un modèle de type enum. Bien que vous devriez faire des efforts pour le mettre en œuvre, mais cela en vaut vraiment la peine.

 public class MyEnum { public static readonly MyEnum Enum1=new MyEnum("This will work",1); public static readonly MyEnum Enum2=new MyEnum("This.will.work.either",2); public static readonly MyEnum[] All=new []{Enum1,Enum2}; private MyEnum(ssortingng name,int value) { Name=name; Value=value; } public ssortingng Name{get;set;} public int Value{get;set;} public override ssortingng ToSsortingng() { return Name; } }