Enum ToString con stringhe facili da usare


282

Il mio enum è costituito dai seguenti valori:

private enum PublishStatusses{
    NotCompleted,
    Completed,
    Error
};

Voglio essere in grado di produrre questi valori in modo intuitivo però.
Non ho bisogno di poter passare di nuovo dalla stringa al valore.


possibile duplicato di enumerazioni di stringhe C #
nawfal,

Risposte:


350

Uso l' Descriptionattributo dallo spazio dei nomi System.ComponentModel. Decora semplicemente l'enum:

private enum PublishStatusValue
{
    [Description("Not Completed")]
    NotCompleted,
    Completed,
    Error
};

Quindi utilizzare questo codice per recuperarlo:

public static string GetDescription<T>(this T enumerationValue)
    where T : struct
{
    Type type = enumerationValue.GetType();
    if (!type.IsEnum)
    {
        throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
    }

    //Tries to find a DescriptionAttribute for a potential friendly name
    //for the enum
    MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString());
    if (memberInfo != null && memberInfo.Length > 0)
    {
        object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

        if (attrs != null && attrs.Length > 0)
        {
            //Pull out the description value
            return ((DescriptionAttribute)attrs[0]).Description;
        }
    }
    //If we have no description attribute, just return the ToString of the enum
    return enumerationValue.ToString();
}

12
Questo esempio è più facile da leggere. stackoverflow.com/questions/1415140/...
RayLoveless

31
Ho il sospetto che ci sia un notevole impatto sulle prestazioni nell'uso della riflessione come descritto in questa soluzione. Il codice per il metodo di Will di utilizzare il metodo di estensione ToFriendlyString è molto più facile da capire, e anche le sue prestazioni dovrebbero essere estremamente veloci.
humbads

1
Mi piace la versione che @RayL ha collegato in quanto aggiungerà solo il metodo di estensione a Enums. Se è tutto ciò per cui vuoi usarlo (come indicato con il ArgumentException, allora non c'è motivo per avere il metodo completamente generico.
Krillgar

4
Significa che ogni enum ha bisogno del proprio metodo di estensione. Questo è un uso più generale e richiede più lavoro, ma probabilmente vorrai quantificare cosa significa "veloce" prima di decidere le prestazioni.
Ray Booysen,

2
@petar che funziona ma non se vuoi che le stringhe amichevoli vengano visualizzate agli utenti. MY_TYPE avrà il trattino basso e non è personalizzabile.
Ray Booysen,

354

Lo faccio con metodi di estensione:

public enum ErrorLevel
{
  None,
  Low,
  High,
  SoylentGreen
}

public static class ErrorLevelExtensions
{
  public static string ToFriendlyString(this ErrorLevel me)
  {
    switch(me)
    {
      case ErrorLevel.None:
        return "Everything is OK";
      case ErrorLevel.Low:
        return "SNAFU, if you know what I mean.";
      case ErrorLevel.High:
        return "Reaching TARFU levels";
      case ErrorLevel.SoylentGreen:
        return "ITS PEOPLE!!!!";
      default:
        return "Get your damn dirty hands off me you FILTHY APE!";
    }
  }
}

6
Questo è molto più pulito della risposta dell'attributo. Bello!
pennyrave,

3
@pennyrave: Eh. Molti componenti dell'interfaccia utente si aspettano di trovare e utilizzare DisplayNameAttribute e DescriptionAttribute. In effetti, ora, uso questi e un metodo di estensione per ottenere facilmente quei valori.

60
Il problema che vedo in questo è che stai costantemente scrivendo questi metodi di estensione. Con il meccanismo degli attributi, è un modo semplice per decorarlo e chiamare sempre e solo un metodo.
Ray Booysen,

5
Non sono sicuro cosa intendi?
Ray Booysen,

9
È meglio, a mio avviso, consentire la defaultrestituzione dell'implementazione del caso me.ToString()e fornire solo istruzioni switch case per i valori enum che si desidera sovrascrivere. Nel tuo esempio, capisco che sono tutti diversi ma in casi d'uso reali, sospetto che la maggior parte dei valori enum a parola singola sarà sufficiente e fornirai solo sostituzioni per i valori enum a più parole.
Scott,

78

Forse mi manca qualcosa, ma cosa c'è che non va in Enum.GetName?

public string GetName(PublishStatusses value)
{
    return Enum.GetName(typeof(PublishStatusses), value)
}

modifica: per stringhe facili da usare, è necessario passare attraverso una .resource per completare l'internazionalizzazione / localizzazione e sarebbe probabilmente meglio usare una chiave fissa basata sulla chiave enum piuttosto che un attributo decoratore sulla stessa.


12
Restituisce il valore letterale dell'enum, non un valore user friendly.
Boris Callens,

2
oic - beh, c'è un caso abbastanza grande in cui devi passare attraverso una libreria di risorse stringa basata su questo valore, perché l'alternativa (attributi del decoratore) non supporterà I18N
annakata,

1
Nel caso di I18N, farei in modo che il metodo GetDescription () esegua una ricerca nella stringa di risorse per una stringa tradotta e ricada sulla descrizione e quindi ricada sul valore letterale.
Boris Callens,

3
+1 per MyEnum.ToString () come chiave di risorsa per la localizzazione. lo faccio da anni
jackvsworld il

1
@annakata abbiamo effettivamente esteso il meccanismo degli attributi per includere il supporto per l18N, in realtà è un semplice cambiamento.
Ray Booysen,

23

Ho creato un metodo di estensione inversa per riconvertire la descrizione in un valore enum:

public static T ToEnumValue<T>(this string enumerationDescription) where T : struct
{
    var type = typeof(T);

    if (!type.IsEnum)
        throw new ArgumentException("ToEnumValue<T>(): Must be of enum type", "T");

    foreach (object val in System.Enum.GetValues(type))
        if (val.GetDescription<T>() == enumerationDescription)
            return (T)val;

    throw new ArgumentException("ToEnumValue<T>(): Invalid description for enum " + type.Name, "enumerationDescription");
}

15
Mi dispiace, ma grazie per aver cercato di essere utile! Sebbene questo sia un sito di domande e risposte, le risposte dovrebbero essere un tentativo di rispondere direttamente alla domanda. E la domanda afferma specificamente " Non ho bisogno di essere in grado di passare di nuovo da stringa a valore " . Ancora una volta, grazie!
Jesse,

8
Grazie per le critiche positive. È sempre difficile essere nuovi in ​​un sito e conoscere la sua cultura e le sue sfumature. Sono contento che ci siano persone come te che mettono in chiaro i nuovi ragazzi. Ancora una volta, grazie per non aver scaricato il nuovo ragazzo.
Brian Richardson,

6
@Jesse E 4 anni dopo qualcuno è felice di trovare qui il codice bjrichardson! SO potrebbe essere un sito di domande e risposte, ma ciò non significa che le domande siano morte dopo la risposta.
Giovanni,

18

La soluzione più semplice qui è utilizzare un metodo di estensione personalizzato (almeno in .NET 3.5 - puoi semplicemente convertirlo in un metodo di supporto statico per le versioni precedenti del framework).

public static string ToCustomString(this PublishStatusses value)
{
    switch(value)
    {
        // Return string depending on value.
    }
    return null;
}

Sto assumendo qui che si desidera restituire qualcosa di diverso dal nome effettivo del valore enum (che è possibile ottenere semplicemente chiamando ToString).


Anche se valido, mi piace di più l'attributo. In questo modo posso mettere il mio metodo toSTring in una libreria separata, mettendo la rappresentazione di stringa personalizzata con l'enum stesso
Boris Callens,

1
Giusto. Suppongo che un vantaggio di questo metodo sia che puoi includere un argomento con il metodo specificando alcune variabili di stato, e quindi modificare quale rappresentazione di stringa viene restituita in base a questo.
Noldorin,

1
Sì, tutto dipende dall'ambito del metodo immagino. Mentre il modo Attributo è più generico, la tua soluzione è più localizzata. Alla fine è tutto basato sui bisogni.
Boris Callens,

1
Puoi mettere i metodi di estensione dove vuoi. Devi solo fare riferimento a dove vuoi usarli.

Sì, ma ciò significherebbe che questo metodo di estensione dovrebbe essere riscritto ogni volta che si introduce un nuovo enum per il quale si desidera avere un nome descrittivo. Ciò significherebbe anche che TUTTE le tue applicazioni porterebbero nomi amichevoli per TUTTE le altre tue applicazioni ...
Boris Callens,

13

L'altro post è Java. Non puoi mettere metodi in Enums in C #.

fai qualcosa del genere:

PublishStatusses status = ...
String s = status.ToString();

Se si desidera utilizzare valori di visualizzazione diversi per i valori di enum, è possibile utilizzare Attributi e Riflessione.


3
toString non è sicuro in tutti i casi - un'enum con più voci con lo stesso valore (diciamo per enumerazioni intere) restituirà la chiave del primo valore corrispondente, non la chiave dell'elemento testato, ecco perché si preferisce Enum.GetName
annakata,

4
Beh, era la soluzione più semplice per il suo enum specifico
Lemmy, il

9

Il modo più semplice è solo quello di includere questa classe di estensione nel tuo progetto, funzionerà con qualsiasi enum nel progetto:

public static class EnumExtensions
{
    public static string ToFriendlyString(this Enum code)
    {
        return Enum.GetName(code.GetType(), code);
    }
}

Uso:

enum ExampleEnum
{
    Demo = 0,
    Test = 1, 
    Live = 2
}

...

ExampleEnum ee = ExampleEnum.Live;
Console.WriteLine(ee.ToFriendlyString());

2
È un mistero il motivo per cui questo commento non è quello accettato, o più votato - nessuna riflessione, nessun attributo non necessario, ideale per situazioni semplici in cui l'enum è già ben chiamato. Potresti portare questa risposta un ulteriore passo avanti e consentire l'aggiunta di spazi tra le lettere maiuscole prima di restituire "My Enum".
Vix,

12
Se l'enum è già ben definito, non è necessario alcun metodo di estensione. Basta usare il metodo ToString () esistente. string result = "Result: " + ee;
Giovanni,

Questa dovrebbe essere la risposta migliore. Funziona per qualsiasi enum. Potresti persino implementarlo usando Enum specifico semplicemente cambiando il tipo Enum del parametro nell'Enum reale su cui usarlo.
Juanu Haedo,

6
Questa risposta e tutti i commenti ignorano la richiesta originale di una descrizione estesa. Ragazzi, avete totalmente perso l'esercizio che è quello di restituire qualcosa di diverso dal valore predefinito di ToString. Non voglio sottovalutare tutte le note per questa risposta qui, ma sicuramente lo voglio.
TonyG,

8

Alcune altre opzioni più primitive che evitano classi / tipi di riferimento:

  • Metodo di matrice
  • Metodo nidificato struct

Metodo di matrice

private struct PublishStatusses
{
    public static string[] Desc = {
        "Not Completed",
        "Completed",
        "Error"
    };

    public enum Id
    {
        NotCompleted = 0,
        Completed,
        Error
    };
}

uso

string desc = PublishStatusses.Desc[(int)PublishStatusses.Id.Completed];

Metodo nidificato struct

private struct PublishStatusses
{
    public struct NotCompleted
    {
        public const int Id = 0;
        public const string Desc = "Not Completed";
    }

    public struct Completed
    {
        public const int Id = 1;
        public const string Desc = "Completed";
    }

    public struct Error
    {
        public const int Id = 2;
        public const string Desc = "Error";
    }            
}

uso

int id = PublishStatusses.NotCompleted.Id;
string desc = PublishStatusses.NotCompleted.Desc;

Aggiornamento (03/09/2018)

Un ibrido di metodi di estensione e la prima tecnica sopra.

Preferisco che gli enum siano definiti dove "appartengono" (più vicini alla loro fonte di origine e non in un comune spazio dei nomi globale).

namespace ViewModels
{
    public class RecordVM
    {
        //public enum Enum { Minutes, Hours }
        public struct Enum
        {
            public enum Id { Minutes, Hours }
            public static string[] Name = { "Minute(s)", "Hour(s)" };
        }
    }
}

Il metodo di estensione sembra adatto a un'area comune e la definizione "localizzata" dell'enum ora rende il metodo di estensione più dettagliato.

namespace Common
{
    public static class EnumExtensions
    {
        public static string Name(this RecordVM.Enum.Id id)
        {
            return RecordVM.Enum.Name[(int)id];
        }
    }   
}

Un esempio di utilizzo dell'enum e del suo metodo di estensione.

namespace Views
{
    public class RecordView 
    {
        private RecordDataFieldList<string, string> _fieldUnit;

        public RecordView()
        {
            _fieldUnit.List = new IdValueList<string, string>
            {            
                new ListItem<string>((int)RecordVM.Enum.Id.Minutes, RecordVM.Enum.Id.Minutes.Name()),
                new ListItem<string>((int)RecordVM.Enum.Id.Hours, RecordVM.Enum.Id.Hours.Name())
            };
        }

        private void Update()
        {    
            RecordVM.Enum.Id eId = DetermineUnit();

            _fieldUnit.Input.Text = _fieldUnit.List.SetSelected((int)eId).Value;
        }
    }
}

Nota: in realtà ho deciso di eliminare il Enumwrapper (e l' Namearray), poiché è meglio che le stringhe di nomi provengano da una risorsa (cioè file di configurazione o DB) anziché essere codificate, e perché ho finito per inserire il metodo di estensione nella ViewModelsspazio dei nomi (solo in un diverso file "CommonVM.cs"). Inoltre, tutto .Iddiventa distratto e ingombrante.

namespace ViewModels
{
    public class RecordVM
    {
        public enum Enum { Minutes, Hours }
        //public struct Enum
        //{
        //    public enum Id { Minutes, Hours }
        //    public static string[] Name = { "Minute(s)", "Hour(s)" };
        //}
    }
}

CommonVM.cs

//namespace Common
namespace ViewModels
{
    public static class EnumExtensions
    {
        public static string Name(this RecordVM.Enum id)
        {
            //return RecordVM.Enum.Name[(int)id];
            switch (id)
            {
                case RecordVM.Enum.Minutes: return "Minute(s)";                    
                case RecordVM.Enum.Hours: return "Hour(s)";
                default: return null;
            }
        }
    }   
}

Un esempio di utilizzo dell'enum e del suo metodo di estensione.

namespace Views
{
    public class RecordView 
    {
        private RecordDataFieldList<string, string> _fieldUnit

        public RecordView()
        {
            _fieldUnit.List = new IdValueList<string, string>
            {            
                new ListItem<string>((int)RecordVM.Enum.Id.Minutes, RecordVM.Enum.Id.Minutes.Name()),
                new ListItem<string>((int)RecordVM.Enum.Id.Hours, RecordVM.Enum.Id.Hours.Name())
            };
        }

        private void Update()
        {    
            RecordVM.Enum eId = DetermineUnit();

            _fieldUnit.Input.Text = _fieldUnit.List.SetSelected((int)eId).Value;
        }
    }
}

+ 1-1 = 0 voto: questa soluzione conserva la sintassi di Enum e risolve elegantemente il problema senza riflessione o codice complesso, quindi +1 lì. Ma perde le caratteristiche degli Enum stessi. Quindi, mentre l'IMO è una buona opzione, non risponde alla domanda reale e ottiene un -1. Net 0. Siamo spiacenti, non abbiamo modo di registrarlo meglio in SO.
TonyG,

@TonyG Abbastanza giusto. Dopo aver perso alcune domande sulla valutazione delle competenze .net di pluarlsight.com, ho iniziato a rendermi conto di quanto siano approfondite le analisi di C #, quindi è probabilmente una buona idea almeno conoscere le loro capacità prima di decidere quale metodologia applicare (soprattutto per l'uso pervasivo, refactoring può essere un po 'di tempo;).
Samis,

7

È possibile utilizzare Humanizer pacchetto con Humanize Enums possiblity. Un esempio:

enum PublishStatusses
{
    [Description("Custom description")]
    NotCompleted,
    AlmostCompleted,
    Error
};

quindi è possibile utilizzare Humanizedirettamente il metodo di estensione su enum:

var st1 = PublishStatusses.NotCompleted;
var str1 = st1.Humanize(); // will result in Custom description

var st2 = PublishStatusses.AlmostCompleted;
var str2 = st2.Humanize(); // will result in Almost completed (calculated automaticaly)

Utilizza anche la riflessione e non viene memorizzato nella cache. github.com/Humanizr/Humanizer/blob/…
Konrad

Sarà lento come la soluzione nella prima risposta di Ray
Konrad

5

Rispetto a Ray Booysen, c'è un bug nel codice: Enum ToString con stringhe facili da usare

È necessario tenere conto di più attributi sui valori enum.

public static string GetDescription<T>(this object enumerationValue)
            where T : struct
    {
        Type type = enumerationValue.GetType();
        if (!type.IsEnum)
        {
            throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
        }

        //Tries to find a DescriptionAttribute for a potential friendly name
        //for the enum
        MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString());
        if (memberInfo != null && memberInfo.Length > 0)
        {
            object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

            if (attrs != null && attrs.Length > 0 && attrs.Where(t => t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault() != null)
            {
                //Pull out the description value
                return ((DescriptionAttribute)attrs.Where(t=>t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault()).Description;
            }
        }
        //If we have no description attribute, just return the ToString of the enum
        return enumerationValue.ToString();

4
L'omissione di un controllo per più attributi Descrizione è intenzionale. Se l'enum ne ha due e stai usando per generare una descrizione, mi piacerebbe pensare che sia una circostanza eccezionale. Penso che il vero bug sia che non faccio un Single () per generare un'eccezione. Altrimenti l'intera firma del metodo non ha senso. GetDescription ()? Quale descrizione? Un aggregato?
Ray Booysen,

4
public enum MyEnum
{
    [Description("Option One")]
    Option_One
}

public static string ToDescriptionString(this Enum This)
{
    Type type = This.GetType();

    string name = Enum.GetName(type, This);

    MemberInfo member = type.GetMembers()
        .Where(w => w.Name == name)
        .FirstOrDefault();

    DescriptionAttribute attribute = member != null
        ? member.GetCustomAttributes(true)
            .Where(w => w.GetType() == typeof(DescriptionAttribute))
            .FirstOrDefault() as DescriptionAttribute
        : null;

    return attribute != null ? attribute.Description : name;
}

3
È sempre bello scrivere del testo che spieghi perché questo dovrebbe funzionare e perché gli OP non lo fossero.
phaberest,

Cordiali saluti, le convenzioni del codice C # vogliono variabili locali e parametri del metodo con la lettera iniziale minuscola. Un'eccezione è il thisparametro nei metodi di estensione, che puoi vedere chiamato Thisin molti esempi nel web. Chiamandolo come il suo tipo come hai fatto tu ( Enum Enum) rende il codice meno leggibile.
Massimiliano Kraus,

4

Invece di usare un enum usa una classe statica.

sostituire

private enum PublishStatuses{
    NotCompleted,
    Completed,
    Error
};

con

private static class PublishStatuses{
    public static readonly string NotCompleted = "Not Completed";
    public static readonly string Completed = "Completed";
    public static readonly string Error = "Error";
};

sarà usato così

PublishStatuses.NotCompleted; // "Not Completed"

Problema utilizzando le migliori soluzioni "metodo di estensione":

Un enum privato viene spesso utilizzato all'interno di un'altra classe. La soluzione del metodo di estensione non è valida in quanto deve essere nella sua classe. Questa soluzione può essere privata e integrata in un'altra classe.


2

Mi capita di essere un fan di VB.NET, quindi ecco la mia versione, che combina il metodo DescriptionAttribute con un metodo di estensione. Innanzitutto, i risultati:

Imports System.ComponentModel ' For <Description>

Module Module1
  ''' <summary>
  ''' An Enum type with three values and descriptions
  ''' </summary>
  Public Enum EnumType
    <Description("One")>
    V1 = 1

    ' This one has no description
    V2 = 2

    <Description("Three")>
    V3 = 3
  End Enum

  Sub Main()
    ' Description method is an extension in EnumExtensions
    For Each v As EnumType In [Enum].GetValues(GetType(EnumType))
      Console.WriteLine("Enum {0} has value {1} and description {2}",
        v,
        CInt(v),
        v.Description
      )
    Next
    ' Output:
    ' Enum V1 has value 1 and description One
    ' Enum V2 has value 2 and description V2
    ' Enum V3 has value 3 and description Three
  End Sub
End Module

Roba di base: un enum chiamato EnumType con tre valori V1, V2 e V3. La "magia" si verifica nella chiamata Console.WriteLine in Sub Main (), dove l'ultimo argomento è semplicemente v.Description. Ciò restituisce "One" per V1, "V2" per V2 e "Three" per V3. Questo metodo di descrizione è in realtà un metodo di estensione, definito in un altro modulo chiamato EnumExtensions:

Option Strict On
Option Explicit On
Option Infer Off

Imports System.Runtime.CompilerServices
Imports System.Reflection
Imports System.ComponentModel

Module EnumExtensions
  Private _Descriptions As New Dictionary(Of String, String)

  ''' <summary>
  ''' This extension method adds a Description method
  ''' to all enum members. The result of the method is the
  ''' value of the Description attribute if present, else
  ''' the normal ToString() representation of the enum value.
  ''' </summary>
  <Extension>
  Public Function Description(e As [Enum]) As String
    ' Get the type of the enum
    Dim enumType As Type = e.GetType()
    ' Get the name of the enum value
    Dim name As String = e.ToString()

    ' Construct a full name for this enum value
    Dim fullName As String = enumType.FullName + "." + name

    ' See if we have looked it up earlier
    Dim enumDescription As String = Nothing
    If _Descriptions.TryGetValue(fullName, enumDescription) Then
      ' Yes we have - return previous value
      Return enumDescription
    End If

    ' Find the value of the Description attribute on this enum value
    Dim members As MemberInfo() = enumType.GetMember(name)
    If members IsNot Nothing AndAlso members.Length > 0 Then
      Dim descriptions() As Object = members(0).GetCustomAttributes(GetType(DescriptionAttribute), False)
      If descriptions IsNot Nothing AndAlso descriptions.Length > 0 Then
        ' Set name to description found
        name = DirectCast(descriptions(0), DescriptionAttribute).Description
      End If
    End If

    ' Save the name in the dictionary:
    _Descriptions.Add(fullName, name)

    ' Return the name
    Return name
  End Function
End Module

Poiché la ricerca degli attributi di descrizione Reflectionè lenta, le ricerche vengono anche memorizzate nella cache in un privato Dictionary, che viene popolato su richiesta.

(Ci scusiamo per la soluzione VB.NET - dovrebbe essere relativamente semplice tradurla in C #, e il mio C # è arrugginito su nuovi argomenti come le estensioni)


2

Riepilogo pulito dei suggerimenti sopra riportati con esempio:

namespace EnumExtensions {

using System;
using System.Reflection;

public class TextAttribute : Attribute {
   public string Text;
   public TextAttribute( string text ) {
      Text = text;
   }//ctor
}// class TextAttribute

public static class EnumExtender {

public static string ToText( this Enum enumeration ) {

   MemberInfo[] memberInfo = enumeration.GetType().GetMember( enumeration.ToString() );

   if ( memberInfo != null && memberInfo.Length > 0 ) {

      object[] attributes = memberInfo[ 0 ].GetCustomAttributes( typeof(TextAttribute),  false );

      if ( attributes != null && attributes.Length > 0 ) {
         return ( (TextAttribute)attributes[ 0 ] ).Text;
      }

   }//if

   return enumeration.ToString();

}//ToText

}//class EnumExtender

}//namespace

USO:

using System;
using EnumExtensions;

class Program {

public enum Appearance {

  [Text( "left-handed" ) ]
  Left,

  [Text( "right-handed" ) ]
  Right,

}//enum

static void Main( string[] args ) {

   var appearance = Appearance.Left;
   Console.WriteLine( appearance.ToText() );

}//Main

}//class

1
C'è un attributo [Description ("")] in C #, perché non usarlo?
Stefan Koenen,

Ovviamente usare [Description ("")] è una strada da percorrere. Ma volevo che il campione fosse completo.
sottolineatura

2

Usa Enum.GetName

Dal link sopra ...

using System;

public class GetNameTest {
    enum Colors { Red, Green, Blue, Yellow };
    enum Styles { Plaid, Striped, Tartan, Corduroy };

    public static void Main() {

        Console.WriteLine("The 4th value of the Colors Enum is {0}", Enum.GetName(typeof(Colors), 3));
        Console.WriteLine("The 4th value of the Styles Enum is {0}", Enum.GetName(typeof(Styles), 3));
    }
}
// The example displays the following output:
//       The 4th value of the Colors Enum is Yellow
//       The 4th value of the Styles Enum is Corduroy


1

Questo è un aggiornamento del codice di Ray Booysen che utilizza il metodo GetCustomAttributes generico e LINQ per rendere le cose un po 'più ordinate.

    /// <summary>
    /// Gets the value of the <see cref="T:System.ComponentModel.DescriptionAttribute"/> on an struct, including enums.  
    /// </summary>
    /// <typeparam name="T">The type of the struct.</typeparam>
    /// <param name="enumerationValue">A value of type <see cref="T:System.Enum"/></param>
    /// <returns>If the struct has a Description attribute, this method returns the description.  Otherwise it just calls ToString() on the struct.</returns>
    /// <remarks>Based on http://stackoverflow.com/questions/479410/enum-tostring/479417#479417, but useful for any struct.</remarks>
    public static string GetDescription<T>(this T enumerationValue) where T : struct
    {
        return enumerationValue.GetType().GetMember(enumerationValue.ToString())
                .SelectMany(mi => mi.GetCustomAttributes<DescriptionAttribute>(false),
                    (mi, ca) => ca.Description)
                .FirstOrDefault() ?? enumerationValue.ToString();
    }   

Non riesci a capire perché ne hai bisogno per essere generico? Se hai intenzione di usare la riflessione?
Lee Louviere,

@LeeLouviere Principalmente per evitare il pugilato quando lo struct (tipo di valore) viene passato come parametro.
Richard Anthony Hein,

1
invece numerationValue.GetType () usa: typeof (T).
Slava,

1
Enorme miglioramento di una riga rispetto alla risposta accettata senza perdere (YMMV) la leggibilità. Sì, con typeof (T).
TonyG,

1

Riepilogo ancora più pulito:

using System;
using System.Reflection;

public class TextAttribute : Attribute
{
    public string Text;
    public TextAttribute(string text)
    {
        Text = text;
    }
}  

public static class EnumExtender
{
    public static string ToText(this Enum enumeration)
    {
        var memberInfo = enumeration.GetType().GetMember(enumeration.ToString());
        if (memberInfo.Length <= 0) return enumeration.ToString();

        var attributes = memberInfo[0].GetCustomAttributes(typeof(TextAttribute), false);
        return attributes.Length > 0 ? ((TextAttribute)attributes[0]).Text : enumeration.ToString();
    }
}

Stesso utilizzo del carattere di sottolineatura descritto.


0

Per le bandiere enum compreso.

    public static string Description(this Enum value)
    {
        Type type = value.GetType();

        List<string> res = new List<string>();
        var arrValue = value.ToString().Split(',').Select(v=>v.Trim());
        foreach (string strValue in arrValue)
        {
            MemberInfo[] memberInfo = type.GetMember(strValue);
            if (memberInfo != null && memberInfo.Length > 0)
            {
                object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

                if (attrs != null && attrs.Length > 0 && attrs.Where(t => t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault() != null)
                {
                    res.Add(((DescriptionAttribute)attrs.Where(t => t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault()).Description);
                }
                else
                    res.Add(strValue);
            }
            else
                res.Add(strValue);
        }

        return res.Aggregate((s,v)=>s+", "+v);
    }

0

Nel caso in cui desideri solo aggiungere uno spazio bianco tra le parole, è semplice come

string res = Regex.Replace(PublishStatusses.NotCompleted, "[A-Z]", " $0").Trim();

0

Uso una classe generica per memorizzare le coppie enum / description e una classe helper nidificata per ottenere la descrizione.

L' enum :

enum Status { Success, Fail, Pending }

La classe generica:

Nota: poiché una classe generica non può essere vincolata da un enum, sto invece vincolando da struct e controllando la presenza di enum nel costruttore.

public class EnumX<T> where T : struct
{
    public T Code { get; set; }
    public string Description { get; set; }

    public EnumX(T code, string desc)
    {
        if (!typeof(T).IsEnum) throw new NotImplementedException();

        Code = code;
        Description = desc;
    }

    public class Helper
    {
        private List<EnumX<T>> codes;

        public Helper(List<EnumX<T>> codes)
        {
            this.codes = codes;
        }

        public string GetDescription(T code)
        {
            EnumX<T> e = codes.Where(c => c.Code.Equals(code)).FirstOrDefault();
            return e is null ? "Undefined" : e.Description;
        }
    }
}

Uso:

EnumX<Status>.Helper StatusCodes = new EnumX<Status>.Helper(new List<EnumX<Status>>()
        {
            new EnumX<Status>(Status.Success,"Operation was successful"),
            new EnumX<Status>(Status.Fail,"Operation failed"),
            new EnumX<Status>(Status.Pending,"Operation not complete. Please wait...")
        });

        Console.WriteLine(StatusCodes.GetDescription(Status.Pending));

-2

Penso che il modo migliore (e più semplice) per risolvere il tuo problema sia scrivere un metodo di estensione per il tuo enum:

public static string GetUserFriendlyString(this PublishStatusses status)
    {

    }

1
Qualcuno era 7 anni prima per affermarlo
Steven

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.