Je sais que ce qui suit n’est pas possible car il doit être un int
enum GroupTypes { TheGroup = "OEM", TheOtherGroup = "CMB" }
De ma firebase database, je reçois un champ avec des codes incompréhensibles (OEM et CMB). Je voudrais faire de ce champ un enum ou autre chose compréhensible. La cible étant lisible, la solution doit être concise.
Quelles autres options ai-je?
J’aime utiliser des propriétés dans une classe plutôt que des méthodes, car elles ressemblent davantage à une énumération.
Voici un exemple pour un enregistreur:
public class LogCategory { private LogCategory(ssortingng value) { Value = value; } public ssortingng Value { get; set; } public static LogCategory Trace { get { return new LogCategory("Trace"); } } public static LogCategory Debug { get { return new LogCategory("Debug"); } } public static LogCategory Info { get { return new LogCategory("Info"); } } public static LogCategory Warning { get { return new LogCategory("Warning"); } } public static LogCategory Error { get { return new LogCategory("Error"); } } }
Transmettez des valeurs de chaîne de type sécurisé en tant que paramètre:
public static void Write(ssortingng message, LogCategory logCategory) { var log = new LogEntry { Message = message }; Logger.Write(log, logCategory.Value); }
Usage:
Logger.Write("This is almost like an enum.", LogCategory.Info);
Vous pouvez également utiliser le modèle d’extension:
public enum MyEnum { [Description("Ssortingng 1")] V1= 1, [Description("Ssortingng 2")] V2= 2 }
Votre classe d’extension
public static class MyEnumExtensions { public static ssortingng ToDescriptionSsortingng(this MyEnum val) { DescriptionAtsortingbute[] atsortingbutes = (DescriptionAtsortingbute[])val.GetType().GetField(val.ToSsortingng()).GetCustomAtsortingbutes(typeof(DescriptionAtsortingbute), false); return atsortingbutes.Length > 0 ? atsortingbutes[0].Description : ssortingng.Empty; } }
usage:
MyEnum myLocal = MyEnum.V1; print(myLocal.ToDescriptionSsortingng());
Que diriez-vous d’utiliser une classe statique avec des constantes? Le code client ne sera pas différent des énumérations.
static class GroupTypes { public const ssortingng TheGroup = "OEM"; public const ssortingng TheOtherGroup = "CMB"; } void DoSomething(GroupTypes groupType) { if(groupType == GroupTypes.TheOtherGroup) { //Launch nuclear bomb } }
Vous pouvez append des atsortingbuts aux éléments de l’énumération, puis utiliser la reflection pour obtenir les valeurs des atsortingbuts.
Vous devrez utiliser le spécificateur “field” pour appliquer les atsortingbuts, comme ceci:
enum GroupTypes { [field:Description("OEM")] TheGroup, [field:Description("CMB")] TheOtherGroup }
Vous réfléchirez alors sur les champs statiques du type de l’énumération (ici les GroupTypes) et récupérez la DescriptionAtsortingbute
pour la valeur que vous recherchiez en utilisant la reflection:
public static DescriptionAtsortingbute GetEnumDescriptionAtsortingbute( this T value) where T : struct { // The type of the enum, it will be reused. Type type = typeof(T); // If T is not an enum, get out. if (!type.IsEnum) throw new InvalidOperationException( "The type parameter T must be an enum type."); // If the value isn't defined throw an exception. if (!Enum.IsDefined(type, value)) throw new InvalidEnumArgumentException( "value", Convert.ToInt32(value), type); // Get the static field for the value. FieldInfo fi = type.GetField(value.ToSsortingng(), BindingFlags.Static | BindingFlags.Public); // Get the description atsortingbute, if there is one. return fi.GetCustomAtsortingbutes(typeof(DescriptionAtsortingbute), true). Cast().SingleOrDefault(); }
J’ai choisi de retourner le DescriptionAtsortingbute
lui-même ci-dessus, dans le cas où vous voulez être en mesure de déterminer si l’atsortingbut est même appliqué ou non.
Vous pouvez le faire très facilement en fait. Utilisez le code suivant.
enum GroupTypes { OEM, CMB };
Ensuite, lorsque vous souhaitez obtenir la valeur de chaîne de chaque élément enum, utilisez simplement la ligne de code suivante.
Ssortingng oemSsortingng = Enum.GetName(typeof(GroupTypes), GroupTypes.OEM);
J’ai utilisé cette méthode avec succès par le passé, et j’ai également utilisé une classe de constantes pour contenir les constantes de chaîne, les deux fonctionnent assez bien, mais j’ai tendance à préférer cela.
Créez une seconde énumération pour votre firebase database contenant les éléments suivants:
enum DBGroupTypes { OEM = 0, CMB = 1 }
Maintenant, vous pouvez utiliser Enum.Parse pour récupérer la valeur DBGroupTypes correcte à partir des chaînes “OEM” et “CMB”. Vous pouvez ensuite les convertir en int et récupérer les valeurs correctes à partir de l’énumération correcte que vous souhaitez utiliser dans votre modèle.
Utilisez une classe.
Edit: Meilleur exemple
class StarshipType { private ssortingng _Name; private static List _StarshipTypes = new List (); public static readonly StarshipType Ultralight = new StarshipType("Ultralight"); public static readonly StarshipType Light = new StarshipType("Light"); public static readonly StarshipType Mediumweight = new StarshipType("Mediumweight"); public static readonly StarshipType Heavy = new StarshipType("Heavy"); public static readonly StarshipType Superheavy = new StarshipType("Superheavy"); public ssortingng Name { get { return _Name; } private set { _Name = value; } } public static IList StarshipTypes { get { return _StarshipTypes; } } private StarshipType(ssortingng name, int systemRatio) { Name = name; _StarshipTypes.Add(this); } public static StarshipType Parse(ssortingng toParse) { foreach (StarshipType s in StarshipTypes) { if (toParse == s.Name) return s; } throw new FormatException("Could not parse ssortingng."); } }
Essayez d’append des constantes à une classe statique. Vous ne vous retrouvez pas avec un Type, mais vous avez des constantes organisées et lisibles:
public static class GroupTypes { public const ssortingng TheGroup = "OEM"; public const ssortingng TheOtherGroup = "CMB" }
Voici la méthode d’extension que j’ai utilisée pour obtenir la valeur enum sous forme de chaîne. D’abord, voici l’énumération.
public enum DatabaseEnvironment { [Description("AzamSharpBlogDevDatabase")] Development = 1, [Description("AzamSharpBlogQADatabase")] QualityAssurance = 2, [Description("AzamSharpBlogTestDatabase")] Test = 3 }
L’atsortingbut Description provient de System.ComponentModel.
Et voici ma méthode d’extension:
public static ssortingng GetValueAsSsortingng(this DatabaseEnvironment environment) { // get the field var field = environment.GetType().GetField(environment.ToSsortingng()); var customAtsortingbutes = field.GetCustomAtsortingbutes(typeof (DescriptionAtsortingbute), false); if(customAtsortingbutes.Length > 0) { return (customAtsortingbutes[0] as DescriptionAtsortingbute).Description; } else { return environment.ToSsortingng(); } }
Maintenant, vous pouvez accéder à l’énumération en tant que valeur de chaîne en utilisant le code suivant:
[TestFixture] public class when_getting_value_of_enum { [Test] public void should_get_the_value_as_ssortingng() { Assert.AreEqual("AzamSharpBlogTestDatabase",DatabaseEnvironment.Test.GetValueAsSsortingng()); } }
Une autre façon de résoudre le problème consiste à avoir une énumération et un tableau de chaînes qui mapperont les valeurs d’énumération avec la liste des chaînes:
public enum GroupTypes { TheGroup = 0, TheOtherGroup } ssortingng[] GroupTypesStr = { "OEM", "CMB" };
vous pouvez l’utiliser comme ceci:
Log.Write(GroupTypesStr[(int)GroupTypes.TheOtherGroup]);
Il demandera à CMB
AVANTAGES:
LES INCONVÉNIENTS:
Avez-vous envisagé une table de consultation à l’aide d’un dictionnaire?
enum GroupTypes { TheGroup, TheOtherGroup } Dictionary GroupTypeLookup = new Dictionary(); // initialize lookup table: GroupTypeLookup.Add("OEM", TheGroup); GroupTypeLookup.Add("CMB", TheOtherGroup);
Vous pouvez ensuite utiliser GroupTypeLookup.TryGetValue () pour rechercher une chaîne lorsque vous la lisez.
Réponse par Even:
public class LogCategory { private LogCategory(ssortingng value) { Value = value; } public ssortingng Value { get; set; } public static LogCategory Trace { get { return new LogCategory("Trace"); } } public static LogCategory Debug { get { return new LogCategory("Debug"); } } public static LogCategory Info { get { return new LogCategory("Info"); } } public static LogCategory Warning { get { return new LogCategory("Warning"); } } public static LogCategory Error { get { return new LogCategory("Error"); } } }
Je voulais juste append un moyen d’imiter le basculement avec les énumérations basées sur les classes:
public void Foo(LogCategory logCategory){ var @switch = new Dictionary{ {LogCategory.Trace, ()=>Console.Writeline("Trace selected!")}, {LogCategory.Debug, ()=>Console.Writeline("Debug selected!")}, {LogCategory.Error, ()=>Console.Writeline("Error selected!")}}; //will print one of the line based on passed argument @switch[logCategory](); }
C # ne prend pas en charge les chaînes énumérées, mais dans la plupart des cas, vous pouvez utiliser une liste ou un dictionnaire pour obtenir l’effet souhaité.
Par exemple, pour imprimer les résultats de réussite / échec:
List PassFail = new List { "FAIL", "PASS" }; bool result = true; Console.WriteLine("Test1: " + PassFail[result.GetHashCode()]);
Je ferais une classe et éviterais un enum. Et puis, avec l’utilisation d’un gestionnaire de type, vous pouvez créer l’object lorsque vous le récupérez depuis la firebase database.
C’EST À DIRE:
public class Group { public ssortingng Value{ get; set; } public Group( ssortingng value ){ Value = value; } public static Group TheGroup() { return new Group("OEM"); } public static Group OtherGroup() { return new Group("CMB"); } }
Je voudrais juste créer un dictionnaire et utiliser le code comme clé.
Edit: Pour répondre au commentaire concernant la recherche inversée (trouver la clé), cela ne serait pas très efficace. Si cela est nécessaire, j’écrirais une nouvelle classe pour la gérer.
Ma première question – Avez-vous access à la firebase database elle-même? Cela devrait être normalisé dans la firebase database, idéalement, sinon, toute solution risque de générer des erreurs. D’après mon expérience, les champs de données contenant “OEM” et “CMB” ont tendance à avoir des éléments comme “oem” et d’autres “données de la merde” mélangés au fil du temps …. Si vous pouvez le normaliser, vous pouvez utiliser la clé dans la table contenant les éléments comme votre Enum, et vous avez terminé, avec une structure beaucoup plus propre.
Si ce n’est pas disponible, je créerais votre Enum et créerais un cours pour parsingr votre chaîne dans Enum pour vous. Cela vous donnerait au moins une certaine souplesse dans la gestion des entrées non standard et une plus grande flexibilité pour le recouvrement des erreurs ou la gestion des erreurs que pour les solutions de contournement utilisant Enum.Parse / Reflection / etc. Un dictionnaire fonctionnerait, mais pourrait tomber en panne si vous avez des problèmes, etc.
Je vous recommande d’écrire un cours afin que vous puissiez faire:
// I renamed this to GroupType, since it sounds like each element has a single type... GroupType theType = GroupTypeParser.GetGroupType(theDBSsortingng);
Cela préserve la plus grande partie de votre lisibilité sans avoir à modifier la firebase database.
Si je comprends bien, vous avez besoin d’une conversion de chaîne en enum:
enum GroupTypes { Unknown = 0, OEM = 1, CMB = 2 } static GroupTypes StrToEnum(ssortingng str){ GroupTypes g = GroupTypes.Unknown; try { object o = Enum.Parse(typeof(GroupTypes), str, true); g = (GroupTypes)(o ?? 0); } catch { } return g; } // then use it like this GroupTypes g1 = StrToEnum("OEM"); GroupTypes g2 = StrToEnum("bad value");
Vous pouvez le rendre plus sophistiqué avec des génériques pour le type enum si vous le souhaitez.
Dans VS 2015, vous pouvez utiliser nameof
public class LogCategory { public static ssortingng Trace; public static ssortingng Debug; public static ssortingng Info; public static ssortingng Warning; public static ssortingng Error; }
Usage:
Logger.Write("This is almost like an enum.", nameof(LogCategory.Info));
public class DataType { private readonly ssortingng value; private static readonly Dictionary predefinedValues; public static readonly DataType Json = new DataType("json"); public static readonly DataType Xml = new DataType("xml"); public static readonly DataType Text = new DataType("text"); public static readonly DataType Html = new DataType("html"); public static readonly DataType Binary = new DataType("binary"); static DataType() { predefinedValues = new Dictionary(); predefinedValues.Add(Json.Value, Json); predefinedValues.Add(Xml.Value, Xml); predefinedValues.Add(Text.Value, Text); predefinedValues.Add(Html.Value, Html); predefinedValues.Add(Binary.Value, Binary); } private DataType(ssortingng value) { this.value = value; } public static DataType Parse(ssortingng value) { var exception = new FormatException($"Invalid value for type {nameof(DataType)}"); if (ssortingng.IsNullOrEmpty(value)) throw exception; ssortingng key = value.ToLower(); if (!predefinedValues.ContainsKey(key)) throw exception; return predefinedValues[key]; } public ssortingng Value { get { return value; } } }
Si vous essayez de rendre votre code lisible:
class GroupTypes { public static final Ssortingng (whatever oem stands for) = "OEM"; public static final Ssortingng (whatever cmb stands for) = "CMB"; ... }
et si vous en avez besoin d’une liste, incluez ces finales dans une liste finale statique
Si vous essayez de rendre votre application lisible, ajoutez:
public static final Map groupsByDbValue; static { groupsByDbValue = new HashMap(); groupsByDbValue.put("OEM", "(whatever OEM stands for)"); groupsByDbValue.put("CMB", "(whatever CMB stands for)"); }
les énumérations dans C # sont limitées aux types numériques entiers sous-jacents (octet, sbyte, short, ushort, int, uint, long et ulong). Vous ne pouvez pas les associer à une valeur sous-jacente basée sur un caractère ou une chaîne.
Une approche différente pourrait consister à définir un dictionnaire de type Dictionary
C’est une manière de l’utiliser comme un paramètre fortement typé ou comme une chaîne :
public class ClassLikeEnum { public ssortingng Value { get; private set; } ClassLikeEnum(ssortingng value) { Value = value; } public static implicit operator ssortingng(ClassLikeEnum c) { return c.Value; } public static readonly ClassLikeEnum C1 = new ClassLikeEnum("RandomSsortingng1"); public static readonly ClassLikeEnum C2 = new ClassLikeEnum("RandomSsortingng2"); }
Vous pouvez utiliser deux énumérations. Un pour la firebase database et l’autre pour la lisibilité.
Vous devez juste vous assurer qu’ils restnt synchronisés, ce qui semble être un petit coût. Vous n’êtes pas obligé de définir les valeurs, il suffit de définir les positions de la même façon, mais en définissant les valeurs, il est très clair que les deux énumérations sont liées et empêche les erreurs de réorganiser les membres enum. Et un commentaire permet à l’équipe de maintenance de savoir que ces informations sont liées et doivent être synchronisées.
// keep in sync with GroupTypes public enum GroupTypeCodes { OEM, CMB } // keep in sync with GroupTypesCodes public enum GroupTypes { TheGroup = GroupTypeCodes.OEM, TheOtherGroup = GroupTypeCodes.CMB }
Pour l’utiliser, vous devez d’abord convertir le code:
GroupTypes myGroupType = GroupTypes.TheGroup; ssortingng valueToSaveIntoDatabase = ((GroupTypeCodes)myGroupType).ToSsortingng();
Ensuite, si vous voulez le rendre encore plus pratique, vous pouvez append une fonction d’extension qui ne fonctionne que pour ce type d’énumération:
public static ssortingng ToSsortingng(this GroupTypes source) { return ((GroupTypeCodes)source).ToSsortingng(); }
et vous pouvez alors juste faire:
GroupTypes myGroupType = GroupTypes.TheGroup; ssortingng valueToSaveIntoDatabase = myGroupType.ToSsortingng();
Un petit ajustement à la méthode Glennular Extension, vous pouvez donc utiliser l’extension sur d’autres choses que celles d’ENUM;
using System; using System.ComponentModel; namespace Extensions { public static class T_Extensions { /// /// Gets the Description Atsortingbute Value /// /// Entity Type /// Variable /// The value of the Description Atsortingbute or an Empty Ssortingng public static ssortingng Description(this T t) { DescriptionAtsortingbute[] atsortingbutes = (DescriptionAtsortingbute[])t.GetType().GetField(t.ToSsortingng()).GetCustomAtsortingbutes(typeof(DescriptionAtsortingbute), false); return atsortingbutes.Length > 0 ? atsortingbutes[0].Description : ssortingng.Empty; } } }
Ou en utilisant Linq
using System; using System.ComponentModel; using System.Linq; namespace Extensions { public static class T_Extensions { public static ssortingng Description(this T t) => ((DescriptionAtsortingbute[])t ?.GetType() ?.GetField(t?.ToSsortingng()) ?.GetCustomAtsortingbutes(typeof(DescriptionAtsortingbute), false)) ?.Select(a => a?.Description) ?.FirstOrDefault() ?? ssortingng.Empty; } }
Je cherchais essentiellement la réponse de Reflection par @ArthurC
Juste pour étendre un peu sa réponse, vous pouvez le rendre encore meilleur en ayant une fonction générique:
// If you want for a specific Enum private static ssortingng EnumSsortingngValue(GroupTypes e) { return EnumSsortingngValue(e); } // Generic private static ssortingng EnumSsortingngValue(T enumInstance) { return Enum.GetName(typeof(T), enumInstance); }
Ensuite, vous pouvez simplement envelopper ce que vous avez
EnumSsortingngValue(GroupTypes.TheGroup) // if you incorporate the top part
ou
EnumSsortingngValue(GroupTypes.TheGroup) // if you just use the generic
Basé sur d’autres opinions, c’est ce que je trouve. Cette approche évite d’avoir à taper .Value où vous voulez obtenir la valeur constante.
J’ai une classe de base pour toutes les énumérations de chaînes comme ceci:
using System; using Newtonsoft.Json; [JsonConverter(typeof(ConstantConverter))] public class SsortingngEnum: IConvertible { public ssortingng Value { get; set; } protected SsortingngEnum(ssortingng value) { Value = value; } public static implicit operator ssortingng(SsortingngEnum c) { return c.Value; } public ssortingng ToSsortingng(IFormatProvider provider) { return Value; } public TypeCode GetTypeCode() { throw new NotImplementedException(); } public bool ToBoolean(IFormatProvider provider) { throw new NotImplementedException(); } //The same for all the rest of IConvertible methods }
Le JsonConverter est comme ceci:
using System; using Newtonsoft.Json; class ConstantConverter : JsonConverter { public override bool CanConvert(Type objectType) { return true; } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { throw new NotImplementedException(); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { if (value == null) { serializer.Serialize(writer, null); } else { serializer.Serialize(writer, value.ToSsortingng()); } } }
Et un enum de chaîne réel sera quelque chose comme ceci:
public sealed class Colors : SsortingngEnum { public static Colors Red { get { return new Catalog("Red"); } } public static Colors Yellow { get { return new Catalog("Yellow"); } } public static Colors White { get { return new Catalog("White"); } } private Colors(ssortingng value) : base(value) { } }
Et avec cela, vous pouvez simplement utiliser Color.Red pour sérialiser même à json sans utiliser la propriété Value
J’ai même implémenté quelques énumérations comme suggéré par @Even (via class X
et public static X
), juste pour savoir plus tard que ces jours-ci, à partir de .Net 4.5, il y a la bonne méthode ToSsortingng()
.
Maintenant, je réimplémente tout dans les énumérations.
Je n’avais besoin de rien de robuste comme de stocker la chaîne dans les atsortingbuts. J’avais juste besoin de transformer quelque chose comme MyEnum.BillEveryWeek
en “facture chaque semaine” ou MyEnum.UseLegacySystem
dans “use legacy system” – en gros, diviser l’énumération par son chameau en mots minuscules individuels.
public static ssortingng UnCamelCase(this Enum input, ssortingng delimiter = " ", bool preserveCasing = false) { var characters = input.ToSsortingng().Select((x, i) => { if (i > 0 && char.IsUpper(x)) { return delimiter + x.ToSsortingng(CultureInfo.InvariantCulture); } return x.ToSsortingng(CultureInfo.InvariantCulture); }); var result = preserveCasing ? ssortingng.Concat(characters) : ssortingng.Concat(characters).ToLower(); var lastComma = result.LastIndexOf(", ", SsortingngComparison.Ordinal); if (lastComma > -1) { result = result.Remove(lastComma, 2).Insert(lastComma, " and "); } return result; }
MyEnum.UseLegacySystem.UnCamelCase()
“Utiliser le système hérité”
Si vous avez plusieurs indicateurs définis, cela se transformera en un simple anglais (délimité par des virgules sauf un “et” à la place de la dernière virgule).
var myCustomerBehaviour = MyEnum.BillEveryWeek | MyEnum.UseLegacySystem | MyEnum.ChargeTaxes; Console.WriteLine(myCustomerBehaviour.UnCamelCase()); //outputs "bill every week, use legacy system and charge taxes"
J’ai fait quelque chose comme ça;
public enum BusinessUnits { NEW_EQUIPMENT = 0, USED_EQUIPMENT = 1, RENTAL_EQUIPMENT = 2, PARTS = 3, SERVICE = 4, OPERATOR_TRAINING = 5 } public class BusinessUnitService { public static ssortingng SsortingngBusinessUnits(BusinessUnits BU) { switch (BU) { case BusinessUnits.NEW_EQUIPMENT: return "NEW EQUIPMENT"; case BusinessUnits.USED_EQUIPMENT: return "USED EQUIPMENT"; case BusinessUnits.RENTAL_EQUIPMENT: return "RENTAL EQUIPMENT"; case BusinessUnits.PARTS: return "PARTS"; case BusinessUnits.SERVICE: return "SERVICE"; case BusinessUnits.OPERATOR_TRAINING: return "OPERATOR TRAINING"; default: return Ssortingng.Empty; } } }
Appelle ça avec ça;
BusinessUnitService.SsortingngBusinessUnits(BusinessUnits.PARTS)
Pourquoi ne pas simplement utiliser ToSsortingng () sur les types Enum?
private enum LogType { Error, Warning, Info}; private WriteLog(ssortingng message, LogType logType) { Log.Write(message, logType.ToSsortingng()); }