2009-07-08 11 views
24

Dal momento che l'enumerazione utilizza numeri interi, quale altra struttura posso usare per darmi l'accesso enum simile al valore legato al nome:Enumerare con tipo di restituzione diverso da stringa?

[So che questo è sbagliato, alla ricerca di un'alternativa]

private enum Project 
    { 
     Cleanup = new Guid("2ED3164-BB48-499B-86C4-A2B1114BF1"), 
     Maintenance = new Guid("39D31D4-28EC-4832-827B-A11129EB2"), 
     Upgrade = new Guid("892F865-E38D-46D7-809A-49510111C1"), 
     Sales = new Guid("A5690E7-1111-4AFB-B44D-1DF3AD66D435"), 
     Replacement = new Guid("11E5CBA2-EDDE-4ECA-BDFD-63BDBA725C8C"), 
     Modem = new Guid("6F686C73-504B-111-9A0B-850C26FDB25F"), 
     Audit = new Guid("30558C7-66D9-4189-9BD9-2B87D11190"), 
     Queries = new Guid("9985242-516A-4151-B7DD-851112F562") 
    } 

EDIT 2014-07-20

Questa è una nuova risposta a questa domanda. Usando la classe Attribute con un metodo helper, definisci gli attributi extra necessari sul tuo enum.

public enum MultiValueEnum 
    { 
     [FooAttribute("alpha", 20d, true)] 
     First, 
     [FooAttribute("beta", 40.91d, false)] 
     Second, 
     [FooAttribute("gamma", 1.2d, false)] 
     Third, 
    }  

    public class FooAttribute : Attribute 
      { 
       internal FooAttribute(string name, double percentage, bool isGood) 
       { 
        this.Name = name; 
        this.Percentage = (decimal)percentage; 
        this.IsGood = isGood; 
       } 
       public string Name { get; private set; } 
       public decimal Percentage { get; private set; } 
       public bool IsGood { get; private set; } 
      } 



    public static TAttribute GetAttribute<TAttribute>(this Enum value) 
     where TAttribute : Attribute 
     { 
      var type = value.GetType(); 
      var name = Enum.GetName(type, value); 
      return type.GetField(name) 
       .GetCustomAttributes(false) 
       .OfType<TAttribute>() 
       .SingleOrDefault(); 
     } 

che rende questo facile:

 MultiValueEnum enumVar = MultiValueEnum.First; 
     var enumStringValue = enumVar.GetAttribute<FooAttribute>().Name; 
     var enumValueDecimal = enumVar.GetAttribute<FooAttribute>().Percentage; 
     var enumBool = enumVar.GetAttribute<FooAttribute>().IsGood; 

risposta

22

Altrimenti è possibile creare un Attributo personalizzato per l'enumerazione, che può contenere il Guid.

Qualcosa accanto a queste linee:

class EnumGuid : Attribute 
{ 
    public Guid Guid; 

    public EnumGuid(string guid) 
    { 
     Guid = new Guid(guid); 
    } 
} 

E che si dovrà usare in questo modo:

enum Project 
{ 
    [EnumGuid("2ED3164-BB48-499B-86C4-A2B1114BF1")] 
    Cleanup = 1, 
    [EnumGuid("39D31D4-28EC-4832-827B-A11129EB2")] 
    Maintenance = 2 
    // and so forth, notice the integer value isn't supposed to be used, 
    // it's merely there because not assigning any value is a performance overhead. 
} 

E infine si può (faccio sempre questo) creare un'estensione per ottenere facilmente la guid:

static Guid GetEnumGuid(this Enum e) 
{ 
    Type type = e.GetType(); 

    MemberInfo[] memInfo = type.GetMember(e.ToString()); 

    if (memInfo != null && memInfo.Length > 0) 
    { 
     object[] attrs = memInfo[0].GetCustomAttributes(typeof(EnumGuid),false); 
     if (attrs != null && attrs.Length > 0) 
      return ((EnumGuid)attrs[0]).Guid; 
    } 

    throw new ArgumentException("Enum " + e.ToString() + " has no EnumGuid defined!"); 
} 

Così, alla fine tutto quello che dovete con le enumerazioni è:

Guid guid = Project.Cleanup.GetEnumGuid(); 

Io uso questo approccio per allegare descrizioni a enumerazioni, in genere stringhe più lunghe contenenti spazi, che quindi non possono essere utilizzate come nomi.

+3

Questa soluzione non costruirà per me. Tuttavia, se si modifica il costruttore su EnumGuid per prendere la stringa e quindi creare il guid da questa stringa lo farà. classe pubblica EnumGuid: Attributo { Guida al pubblico {get; set privato; } public EnumGuid (String s) { this.Guid = Guid.Parse (s); } } – Drauka

+0

Sì, sembra che sia necessario utilizzare i tipi primitivi per i costruttori enum, consultare: http://stackoverflow.com/questions/25859094/an-attribute-argument-must-be-a-constant-expression-create- a-attributo-di. Tuttavia, come dichiarato da @Druaka, converti una stringa in una guida all'interno del costruttore e tutto va bene. – puddinman13

11

Ho visto questo metodo (struct) utilizzato da SubSonic per memorizzare i nomi di colonna e la tabella.

internal struct Project 
{ 
    public static Guid Cleanup = new Guid("2ED3164-BB48-499B-86C4-A2B1114BF1"); 
    public static Guid Maintenance = new Guid("39D31D4-28EC-4832-827B-A129EB2"); 
    public static Guid Upgrade = new Guid("892F865-E38D-46D7-809A-49510111C1"); 
    public static Guid Sales = new Guid("A5690E7-1111-4AFB-B44D-1DF3AD66D435"); 
    public static Guid Replacement = new Guid("11E5CBA2-EDDE-4ECA-BD63-B725C8C"); 
    public static Guid Modem = new Guid("6F686C73-504B-111-9A0B-850C26FDB25F"); 
    public static Guid Audit = new Guid("30558C7-66D9-4189-9BD9-2B87D11190"); 
    public static Guid Queries = new Guid("9985242-516A-4151-B7DD-851112F562"); 
} 

EDIT: - Grazie per il commento sulle carenze nel codice. In primo luogo verrà compilato se le stringhe di guida non sono invalide. Come per non creare istanze di accesso variabili sì hanno bisogno di essere

+1

Impossibile accedere ai campi privati ​​nelle strutture, inoltre non è possibile inizializzare i campi come si fa in una struttura. – leppie

+3

Devono essere anche statici, perché il tuo esempio funzioni. – leppie

+0

Non dovresti essere in grado di creare istanze di questa struttura, poiché agisce solo come contenitore –

0

Di fronte a questo tipo di problema che ho usato le strutture con const come membri pubblici public static:

public struct FileExtensions 
{ 
    public const string ProcessingExtension = ".lck"; 
    public const string ProcessedExtension = ".xml"; 
    public const string FailedExtension = ".failed"; 
    public const string CsvExtension = ".csv"; 
} 
+1

Una classe avrà più senso, dato che è possibile derivarne e estendere le costanti. – leppie

+0

Non deriverei da una classe il cui unico scopo è quello di contenere valori costanti, poiché il polimorfismo non avrebbe molto senso. Continuerò invece ad aggiungere costanti correlate alla stessa classe, oa crearne di nuove per nuovi insiemi di costanti. –

+0

@ enrico: ci sono alcuni vantaggi, come i campi dei genitori in ambito. – leppie

0

Si potrebbe creare una classe statica che contiene solo valori costanti. Ad esempio:

internal static class Project 
{ 
    public static readonly Guid Cleanup = new Guid("2ED3164-BB48-499B-86C4-A2B1114BF1"); 
    public static readonly Guid Maintenance = new Guid("39D31D4-28EC-4832-827B-A11129EB2"); 
    public static readonly Guid Upgrade = new Guid("892F865-E38D-46D7-809A-49510111C1"); 
} 

questo modo la classe funge semplicemente da un contenitore e l'oggetto non può essere creato da esso.

In VB questo sarebbe un modulo:

Friend Module Project 
    Public Shared ReadOnly Cleanup As Guid = New Guid("2ED3164-BB48-499B-86C4-A2B1114BF1") 
    Public Shared ReadOnly Maintenance As Guid = New Guid("39D31D4-28EC-4832-827B-A11129EB2") 
    Public Shared ReadOnly Upgrade As Guid = New Guid("892F865-E38D-46D7-809A-49510111C1") 
End Module 
+1

Guid può essere const .... – leppie

+1

Hai ragione, li ho modificati in campi di sola lettura –

+0

Qui andiamo ancora. Le classi statiche non hanno membri di istanza! – leppie

0

Il tipo enum può only support il integral types (eccetto char) come valore. Si potrebbe comunque usare qualcosa come un dizionario per fare la ricerca di un nome su un valore.

Dictionary<Guid> lookup = new Dictionary<Guid>(); 
lookup["Cleanup"] = new Guid("2ED3164-BB48-499B-86C4-A2B1114BF1"); 
lookup["Maintenance"] = new Guid("39D31D4-28EC-4832-827B-A11129EB2"); 
lookup["Upgrade"] = new Guid("892F865-E38D-46D7-809A-49510111C1"); 
// etc... 

Un'altra alternativa è disporre di una serie di valori di sola lettura in una classe statica.

public static class Guids 
{ 
    public static readonly Guid Cleanup = new Guid("2ED3164-BB48-499B-86C4-A2B1114BF1"), 
    public static readonly Guid Maintenance = new Guid("39D31D4-28EC-4832-827B-A11129EB2"), 
    public static readonly Guid Upgrade = new Guid("892F865-E38D-46D7-809A-49510111C1"), 
} 
+0

Eccoci di nuovo. Le classi statiche non hanno membri di istanza! – leppie

+0

Buon punto, grazie. Aggiornato – heavyd

5

Probabilmente andrò per il dizionario su questo. Avere una tabella di ricerca in fondo:

public class GuidMapper 
{ 
    private Dictionary<GuidTypes, Guid> mGuidMap = new Dictionary<GuidTypes, Guid>(); 
    public enum GuidTypes: int 
    { 
     Cleanup, 
     Maintenance, 
     Upgrade, 
     Sales, 
     Replacement, 
     Modem, 
     Audit, 
     Queries 
    } 

    public GuidMapper() 
    { 
     mGuidMap.Add(GuidTypes.Cleanup, new Guid("2ED31640-BB48-499B-86C4-A2B1114BF100")); 
     mGuidMap.Add(GuidTypes.Maintenance, new Guid("39D31D40-28EC-4832-827B-A11129EB2000")); 
     mGuidMap.Add(GuidTypes.Upgrade, new Guid("892F8650-E38D-46D7-809A-49510111C100")); 
     mGuidMap.Add(GuidTypes.Sales, new Guid("A5690E70-1111-4AFB-B44D-1DF3AD66D435")); 
     mGuidMap.Add(GuidTypes.Replacement, new Guid("11E5CBA2-EDDE-4ECA-BDFD-63BDBA725C8C")); 
     mGuidMap.Add(GuidTypes.Modem, new Guid("6F686C73-504B-1110-9A0B-850C26FDB25F")); 
     mGuidMap.Add(GuidTypes.Audit, new Guid("30558C70-66D9-4189-9BD9-2B87D1119000")); 
     mGuidMap.Add(GuidTypes.Queries, new Guid("99852420-516A-4151-B7DD-851112F56200")); 
    } 

    public Guid GetGuid(GuidTypes guidType) 
    { 
     if (mGuidMap.ContainsKey(guidType)) 
     { 
      return mGuidMap[guidType]; 
     } 
     return Guid.Empty; 
    } 
} 
2

Se avete bisogno di adeguati enum -come semantica e tipo di sicurezza è possibile utilizzare un modello come questo.

(Si potrebbe carne fuori ulteriormente se hai bisogno di extra come operatori di conversione, GetUnderlyingType, ToString ecc Se si voleva riutilizzare il modello per molteplici enum -come classi con diversi tipi di fondo, allora si potrebbe spostare qualsiasi codice comune in una classe base generica e astratta)

Project x = Project.Cleanup; 
Project y = Project.Cleanup; 
Project z = Project.Maintenance; 

Console.WriteLine(x == y);  // True 
Console.WriteLine(x == z);  // False 
Console.WriteLine(x.Value); // 47801daa-7437-4bfe-a240-9f7c583018a4 

// this line will cause a compiler error 
Console.WriteLine(x == new Guid("47801daa-7437-4bfe-a240-9f7c583018a4")); 

// ... 

public class Project 
{ 
    private Project(Guid v) { Value = v; } 
    public Guid Value { get; private set; } 

    public static readonly Project Cleanup = 
     new Project(new Guid("47801daa-7437-4bfe-a240-9f7c583018a4")); 

    public static readonly Project Maintenence = 
     new Project(new Guid("2548a7f3-7bf4-4533-a6c1-dcbcfcdc26a5")); 

    public static readonly Project Upgrade = 
     new Project(new Guid("ed3c3e73-8e6a-4c09-84ae-7f0876d194aa")); 
} 
Problemi correlati