2011-10-14 4 views
1

Je génère des énumérations dynamiques représentant des ID entiers de ma base de données dans une solution C# ASP.NET. Je voudrais deux choses, bien que ce ne soit pas possible.Custom C# Enum ToString() lors de la génération dynamique

1) Je veux que la méthode .ToString() me donne "345" par exemple, pas le nom de la chaîne de l'enum (l'int qu'il représente comme une chaîne). Chaque réponse à cette question semble ajouter

[Description="Blah"] 
EnumName = 1 

au-dessus de la déclaration et en utilisant une méthode GetDescription(). Je n'ai aucune idée de comment faire cela avec le code dynamique que j'utilise.

2) Je préfère ne pas utiliser un int pour l'utiliser comme tel, je préfère (Enum.Name == 5) par exemple. Si ce n'est pas possible, je vais lancer, mais je ne veux vraiment pas utiliser ((int) Enum.Name)). ToString();

Voici la génération de code dynamique:

public static void Main() 
{ 
    AppDomain domain = AppDomain.CurrentDomain; 

    AssemblyName aName = new AssemblyName("DynamicEnums"); 
    AssemblyBuilder ab = domain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Save); 

    ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll"); 

    List<Type> types = new List<Type>(); 

    foreach(ReferenceType rt in GetTypes()) 
    { 
     EnumBuilder eb = mb.DefineEnum(rt.Name, TypeAttributes.Public, typeof(int)); 

     foreach (Reference r in GetReferences(rt.ID)) 
     { 
      eb.DefineLiteral(NameFix(r.Name), r.ID); 
     } 

     types.Add(eb.CreateType()); 
    } 

    ab.Save(aName.Name + ".dll"); 

    foreach (Type t in types) 
    { 
     foreach (object o in Enum.GetValues(t)) 
     { 
      Console.WriteLine("{0}.{1} = {2}", t, o, ((int) o)); 
     } 

     Console.WriteLine(); 
     //Console.ReadKey(); 
    } 

    Console.WriteLine(); 
    Console.WriteLine("Dynamic Enums Built Successfully."); 
} 

public static string NameFix(string name) 
{ 
    //Strip all non alphanumeric characters 
    string r = Regex.Replace(name, @"[^\w]", ""); 

    //Enums cannot begin with a number 
    if (Regex.IsMatch(r, @"^\d")) 
     r = "N" + r; 

    return r; 
} 

Il peut tout simplement aucun moyen de faire ce que je veux faire, et je serai coincé à l'aide:

(int)Countries.USA //For int value 
((int)Countries.CAN).ToString() //For string representation of int value, ex. "354" 

Toutes les idées?

+0

Je suis absolument sûr que cela doit être un moyen de générer par réflexion l'attribut Description. –

+3

Je ne vois pas vraiment pourquoi vous utilisez 'ENUM'. C'est vraiment utile quand vous écrivez du code et vous pouvez simplement utiliser une certaine valeur avec un joli nom qui vous dit à quoi il sert vraiment. Peut-être vaut-il mieux utiliser un 'dictionnaire', puisque vous le construisez dynamiquement, que 'enum'? –

+0

Je crée la DLL puis la référence dans mes webapps, puis je lie les listes déroulantes/cases à cocher/listes de radiobutton pour avoir les valeurs des ID dans ma base de données. Je veux ensuite faire des choses comme si (Report == Reports.SevenDay) – Ehryk

Répondre

3

Pourriez-vous adapter le modèle d'énumération sécurisé pour faire ce dont vous avez besoin?

public class MyEnum 
{ 
    #region Enum Values 

    // Pre defined values.  
    public static readonly MyEnum ValueOne = new MyEnum(0); 
    public static readonly MyEnum ValueTwo = new MyEnum(1); 

    // All values in existence. 
    private static readonly Dictionary<int, MyEnum> existingEnums = new Dictionary<int, MyEnum>{{ValueOne.Value, ValueOne}, {ValueTwo.Value, ValueTwo}}; 

    #endregion 

    #region Enum Functionality 

    private readonly int Value; 

    private MyEnum(int value) 
    { 
     Value = value; 
    } 

    public static MyEnum GetEnum(int value) 
    { 
     // You will probably want to make this thread-safe. 
     if (!existingEnums.ContainsKey(value)) existingEnums[value] = new MyEnum(value); 

     return existingEnums[value]; 
    } 

    public override string ToString() 
    { 
     return Value.ToString(); 
    } 

    #endregion 
} 

Utilisation:

private void Foo(MyEnum enumVal) 
{ 
    return "Enum Value: " + enumVal; // returns "Enum Value: (integer here) 
} 

Ou:

MyEnum.GetValue(2) == MyEnum.GetValue(4); // false 
MyEnum.GetValue(3) == MyEnum.GetValue(3); // true 
+0

Y a-t-il un moyen de l'utiliser dans la génération dynamique? EnumBuilder eb = mb.DefineEnum (rt.Nom, TypeAttributs.Public, typeof (MyEnum)); – Ehryk

+0

Que voulez-vous faire avec l'énumération après l'avoir créée? Comparer les valeurs pour différents objets? Vous pouvez ajouter une méthode GetEnumInstance (int value) à la classe ci-dessus qui renvoie l'objet existant pour cette valeur (ou le crée s'il n'y en a pas). Je vais ajouter un peu plus de code. – Joey

+0

Je pense que je pourrais faire quelque chose comme ça. Je pourrais avoir une propriété Value() et String pour obtenir chacun quand je le voulais. Existe-t-il cependant un moyen de surcharger le == pour renvoyer un int ou une chaîne? (Ou même les deux en fonction de ce que l'on compare par rapport?) Je vais examiner cela. – Ehryk

3

Vous voulez vraiment convertir la valeur Enum à un string pas le nom? La conversion au type sous-jacent de Enum est le moyen le plus simple d'extraire la valeur. Je pense que vous aurez du mal à obtenir quelque chose de plus court ou plus simple que ((int)...). Si vous ne voulez pas "énumérer" certaines valeurs, ou si vous voulez faire quelque chose de différent, vous pouvez faire votre propre classe de YourEnum qui a essentiellement le casting intégré, la diffusion au besoin semble plus facile et plus lisible.

Peut-être que vous voulez réellement des constantes.

const string Blah = "345"; 

EDIT

J'ai eu une autre idée, vous pouvez écrire une méthode d'extension pour Enum comme celui-ci,

public static class MyExtentions 
{ 
    public static string ValueString(this Enum e) 
    { 
     var ut = Enum.GetUnderlyingType(e.GetType()); 
     var castToString = typeOf(MyExtentions).GetMethod("CastToString"); 
     var gcast = cast.MakeGenericMethod(ut); 
     var gparams = new object[] {e}; 
     return gcast.Invoke(null, gparams).ToString(); 
    } 

    public static string CastToString<T>(object o) 
    { 
     return ((T)o).ToString(); 
    } 

}

Avec cela, vous pouvez appeler ValueString() sur tout Enum instance et obtenir une chaîne de la valeur. Il a clairement utilisé la réflexion pour que la performance ne soit pas incroyable mais je ne pense pas que cela ait de l'importance dans votre cas.

+0

Oui, je veux la valeur entière comme une chaîne. – Ehryk

+0

Hmm, peut-être que const serait mieux, mais j'utilise parfois l'int et parfois la chaîne, donc je voudrais des constantes int. Je voudrais que Countries.USA retourne 120, et Countries.USA.ToString() soit "120". Quelle serait la différence entre Enums et les classes nommées avec const ints en eux? – Ehryk

+0

@Ehryk, je pense que mon édition pourrait être ce que vous cherchez. – Jodrell

2

Lorsque vous utilisez le type de classe Enum, que pensez-vous de l'utilisation de la méthode Enum.Format.

Par exemple:

enum EnumClassA {One, Two, Three, Four}; 

... 

EnumClassA chosenValue = EnumClassA.Three; 

Console.WriteLine("Chosen value is {0}", Enum.Format(typeof(EnumClassA), chosenValue, "d")); 

Cela devrait donner une sortie:

Chosen value is 2 

modifier

Une autre option serait:

EnumClassA.Three.ToString("d"); //Enum.Name.ToString("d") 

Cela donne également une valeur de chaîne de "2".

** modifier **

Comme vous faites des comparaisons pour voir si la valeur existe dans vos énumérations comment sur l'utilisation Enum.IsDefined (EnumType, valeur) qui retourne un bool?

Console.WriteLine("Does the enumClassA contain {0} result is {1}", 5, Enum.IsDefined(typeof(enumClassA), 5)); 

Cela donne une sortie:

Does the enumClassA contain 5 result is False 
+0

Je suis vraiment à la recherche d'une version plus abrégée que int moulages et ToStrings, cela semble un peu plus long. Ce que je fais correspond à des valeurs sélectionnées dans une liste déroulante, liées à ints, qui reviennent à "354". – Ehryk

+0

@Ehryk - Pour le rendre plus court, vous pouvez créer une méthode d'extension pour Enum. chaîne statique publique MakeString (this Enum bla) { return Enum.Format (bla.GetType(), bla, "d"); } –

+0

okay, je ne suis pas sûr qu'il y a. – ChrisBD

2

Je me rends compte que la question a été marquée comme une réponse, mais peut-être en utilisant une extension pourrait être utile?

Il vous permet toujours d'utiliser les énumérations générées de cette façon.

ps. Soyez prudent lorsque vous appelez GetString - n'appelez pas accidentellement ToString à la place!

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Reflection; 
using System.Reflection.Emit; 

namespace ConsoleApplication1 
{ 

    public enum YourEnum 
    { 
     Apples = 1, 
     Pears = 2, 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      foreach (var value in (YourEnum[])Enum.GetValues(typeof(YourEnum))) 
      { 
       int v = value.GetValue(); 
       Console.WriteLine("{0} = {1} (int)", value.ToString(), v); 

       string s = value.GetString(); 
       Console.WriteLine("{0} = {1} (string)", value.ToString(), s); 
      } 
      Console.ReadLine(); 

      //Results: 

      //Apples = 1 (int) 
      //Apples = 1 (string) 
      //Pears = 2 (int) 
      //Pears = 2 (string) 
     } 
    } 

    public static class EnumExtensions 
    { 
     public static int GetValue(this Enum value) 
     { 
      return Convert.ToInt32(value); 
     } 

     public static string GetString(this Enum value) 
     { 
      return Convert.ToInt32(value).ToString(); 
     } 
    } 

} 
Questions connexes