Frage String-Darstellung einer Enum


Ich habe die folgende Aufzählung:

public enum AuthenticationMethod
{
    FORMS = 1,
    WINDOWSAUTHENTICATION = 2,
    SINGLESIGNON = 3
}

Das Problem ist jedoch, dass ich das Wort "FORMS" brauche, wenn ich nach AuthenticationMethod.FORMS und nicht nach der ID 1 frage.

Ich habe die folgende Lösung für dieses Problem gefunden (Verknüpfung):

Zuerst muss ich ein benutzerdefiniertes Attribut namens "StringValue" erstellen:

public class StringValue : System.Attribute
{
    private readonly string _value;

    public StringValue(string value)
    {
        _value = value;
    }

    public string Value
    {
        get { return _value; }
    }

}

Dann kann ich dieses Attribut meinem Enumerator hinzufügen:

public enum AuthenticationMethod
{
    [StringValue("FORMS")]
    FORMS = 1,
    [StringValue("WINDOWS")]
    WINDOWSAUTHENTICATION = 2,
    [StringValue("SSO")]
    SINGLESIGNON = 3
}

Und natürlich brauche ich etwas, um diesen StringValue abzurufen:

public static class StringEnum
{
    public static string GetStringValue(Enum value)
    {
        string output = null;
        Type type = value.GetType();

        //Check first in our cached results...

        //Look for our 'StringValueAttribute' 

        //in the field's custom attributes

        FieldInfo fi = type.GetField(value.ToString());
        StringValue[] attrs =
           fi.GetCustomAttributes(typeof(StringValue),
                                   false) as StringValue[];
        if (attrs.Length > 0)
        {
            output = attrs[0].Value;
        }

        return output;
    }
}

Gut, jetzt habe ich die Werkzeuge, um einen String-Wert für einen Enumerator zu bekommen. Ich kann es dann so benutzen:

string valueOfAuthenticationMethod = StringEnum.GetStringValue(AuthenticationMethod.FORMS);

Okay, all das funktioniert wie ein Zauber, aber ich finde es eine Menge Arbeit. Ich habe mich gefragt, ob es dafür eine bessere Lösung gibt.

Ich habe auch etwas mit einem Wörterbuch und statischen Eigenschaften versucht, aber das war auch nicht besser.


823
2018-01-08 14:15


Ursprung


Antworten:


Versuchen Typ-Safe-Enum Muster.

public sealed class AuthenticationMethod {

    private readonly String name;
    private readonly int value;

    public static readonly AuthenticationMethod FORMS = new AuthenticationMethod (1, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION = new AuthenticationMethod (2, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON = new AuthenticationMethod (3, "SSN");        

    private AuthenticationMethod(int value, String name){
        this.name = name;
        this.value = value;
    }

    public override String ToString(){
        return name;
    }

}

Aktualisieren Explizite (oder implizite) Typumwandlung kann durch durchgeführt werden

  • statisches Feld mit Zuordnung hinzufügen

    private static readonly Dictionary<string, AuthenticationMethod> instance = new Dictionary<string,AuthenticationMethod>();
    
    • n.b. Damit die Initialisierung der Felder "enum member" beim Aufrufen des Instanzkonstruktors keine NullReferenceException auslöst, müssen Sie das Dictionary-Feld vor die Felder "enum member" in Ihrer Klasse stellen. Dies liegt daran, dass Initialisierer für statische Felder in der Deklarationsreihenfolge und vor dem statischen Konstruktor aufgerufen werden, wodurch die seltsame und notwendige, aber verwirrende Situation entsteht, dass der Instanzkonstruktor aufgerufen werden kann, bevor alle statischen Felder initialisiert wurden und bevor der statische Konstruktor aufgerufen wird.
  • Füllen dieses Mapping im Instanzkonstruktor

    instance[name] = this;
    
  • und hinzufügen benutzerdefinierter Typkonvertierungsoperator

    public static explicit operator AuthenticationMethod(string str)
    {
        AuthenticationMethod result;
        if (instance.TryGetValue(str, out result))
            return result;
        else
            throw new InvalidCastException();
    }
    

814
2018-01-08 14:29



Verwenden Sie Methode

Enum.GetName(Type MyEnumType,  object enumvariable)  

wie in (Angenommen Shipper ist eine definierte Enum)

Shipper x = Shipper.FederalExpress;
string s = Enum.GetName(typeof(Shipper), x);

Es gibt eine Reihe anderer statischer Methoden auf der Enum-Klasse, die auch untersucht werden sollten ...


209
2018-01-08 14:19



Sie können auf den Namen und nicht auf den Wert verweisen, indem Sie ToString () verwenden.

Console.WriteLine("Auth method: {0}", AuthenticationMethod.Forms.ToString());

Die Dokumentation ist hier:

http://msdn.microsoft.com/en-us/library/16c1xs4z.aspx

... und wenn Sie Ihre Enums in Pascal Case benennen (wie ThisIsMyEnumValue = 1 usw.), dann könnten Sie eine sehr einfache Regex verwenden, um das freundliche Formular zu drucken:

static string ToFriendlyCase(this string EnumString)
{
    return Regex.Replace(EnumString, "(?!^)([A-Z])", " $1");
}

welches aus jeder beliebigen Zeichenfolge leicht aufgerufen werden kann:

Console.WriteLine("ConvertMyCrazyPascalCaseSentenceToFriendlyCase".ToFriendlyCase());

Ausgänge:

Wandeln Sie meinen verrückten Pascal-Fall-Satz in freundlichen Fall um

Dadurch sparen Sie sich den ganzen Weg um die Häuser herum, erstellen benutzerdefinierte Attribute und fügen diese Ihren Enums hinzu oder verwenden Nachschlagetabellen, um einen Enum-Wert mit einer freundlichen Zeichenfolge zu verbinden. Am besten ist es selbstverwaltend und kann mit jeder beliebigen Pascal Case-Zeichenfolge verwendet werden mehr wiederverwendbar. Natürlich erlaubt es dir nicht, ein zu haben anders freundlicher Name als Ihr enum, das Ihre Lösung zur Verfügung stellt.

Ich mag jedoch Ihre ursprüngliche Lösung für komplexere Szenarien. Sie könnten Ihre Lösung noch einen Schritt weiter bringen und Ihren GetStringValue zu einer Erweiterungsmethode für Ihre Enumeration machen, und dann müssten Sie nicht wie StringEnum.GetStringValue darauf verweisen ...

public static string GetStringValue(this AuthenticationMethod value)
{
  string output = null;
  Type type = value.GetType();
  FieldInfo fi = type.GetField(value.ToString());
  StringValue[] attrs = fi.GetCustomAttributes(typeof(StringValue), false) as StringValue[];
  if (attrs.Length > 0)
    output = attrs[0].Value;
  return output;
}

Sie können dann direkt von Ihrer enum-Instanz aus darauf zugreifen:

Console.WriteLine(AuthenticationMethod.SSO.GetStringValue());

74
2018-01-08 14:20



Leider ist das Nachdenken über Attribute für Enums ziemlich langsam:

Siehe diese Frage: Wer weiß einen schnellen Weg, um benutzerdefinierte Attribute auf einem Enum-Wert zu erhalten?

Das .ToString() ist auch bei Enums ziemlich langsam.

Sie können jedoch Erweiterungsmethoden für Enums schreiben:

public static string GetName( this MyEnum input ) {
    switch ( input ) {
        case MyEnum.WINDOWSAUTHENTICATION:
            return "Windows";
        //and so on
    }
}

Das ist nicht großartig, wird aber schnell sein und keine Reflektion für Attribute oder Feldnamen erfordern.


C # 6 Update

Wenn Sie C # 6 verwenden können, dann das neue nameof Betreiber arbeitet für enums, also nameof(MyEnum.WINDOWSAUTHENTICATION) wird umgewandelt in "WINDOWSAUTHENTICATION" beim KompilierzeitEs ist der schnellste Weg, um Namen zu erhalten.

Beachten Sie, dass dies die explizite Enumeration in eine Inline-Konstante konvertiert, sodass sie für Enums, die Sie in einer Variablen haben, nicht funktioniert. Damit:

nameof(AuthenticationMethod.FORMS) == "FORMS"

Aber...

var myMethod = AuthenticationMethod.FORMS;
nameof(myMethod) == "myMethod"

63
2018-02-11 00:15



Ich benutze eine Erweiterungsmethode:

public static class AttributesHelperExtension
    {
        public static string ToDescription(this Enum value)
        {
            var da = (DescriptionAttribute[])(value.GetType().GetField(value.ToString())).GetCustomAttributes(typeof(DescriptionAttribute), false);
            return da.Length > 0 ? da[0].Description : value.ToString();
        }
}

Jetzt dekoriere die enum mit:

public enum AuthenticationMethod
{
    [Description("FORMS")]
    FORMS = 1,
    [Description("WINDOWSAUTHENTICATION")]
    WINDOWSAUTHENTICATION = 2,
    [Description("SINGLESIGNON ")]
    SINGLESIGNON = 3
}

Wenn du anrufst

AuthenticationMethod.FORMS.ToDescription() Sie erhalten "FORMS".


52
2017-09-06 15:50



Benutze einfach die ToString() Methode

public enum any{Tomato=0,Melon,Watermelon}

Um die Zeichenfolge zu referenzieren Tomato, benutz einfach

any.Tomato.ToString();

36
2018-01-08 14:30



Ich verwende das Description-Attribut aus dem Namespace System.ComponentModel. Einfach die Enumeration dekorieren und dann diesen Code verwenden, um sie zu erhalten:

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)
                {
                    //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();

        }

Als Beispiel:

public enum Cycle : int
{        
   [Description("Daily Cycle")]
   Daily = 1,
   Weekly,
   Monthly
}

Dieser Code eignet sich gut für Enums, wo Sie keinen "Friendly name" benötigen und nur den .ToString () des Enums zurückgeben.


26
2017-09-22 20:46



Sehr einfache Lösung hierfür mit .Net 4.0 und höher. Kein anderer Code wird benötigt.

public enum MyStatus
{
    Active = 1,
    Archived = 2
}

Um die Zeichenfolge einfach zu verwenden:

MyStatus.Active.ToString("f");

oder

MyStatus.Archived.ToString("f");`

Der Wert wird "Aktiv" oder "Archiviert" sein.

Um die verschiedenen String-Formate (das "f" von oben) beim Aufruf zu sehen Enum.ToString Sieh dir das an Aufzählungsformatzeichenfolgen Seite


22
2018-01-20 21:13



Ich mag die Antwort von Jakub Šturc sehr, aber es ist ein Manko, dass man es nicht mit einer switch-case-Anweisung verwenden kann. Hier ist eine leicht modifizierte Version seiner Antwort, die mit einer switch-Anweisung verwendet werden kann:

public sealed class AuthenticationMethod
{
    #region This code never needs to change.
    private readonly string _name;
    public readonly Values Value;

    private AuthenticationMethod(Values value, String name){
        this._name = name;
        this.Value = value;
    }

    public override String ToString(){
        return _name;
    }
    #endregion

    public enum Values
    {
        Forms = 1,
        Windows = 2,
        SSN = 3
    }

    public static readonly AuthenticationMethod FORMS = new AuthenticationMethod (Values.Forms, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION = new AuthenticationMethod (Values.Windows, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON = new AuthenticationMethod (Values.SSN, "SSN");
}

So erhalten Sie alle Vorteile von Jakub Šturcs Antwort, und wir können sie mit einer switch-Anweisung wie folgt verwenden:

var authenticationMethodVariable = AuthenticationMethod.FORMS;  // Set the "enum" value we want to use.
var methodName = authenticationMethodVariable.ToString();       // Get the user-friendly "name" of the "enum" value.

// Perform logic based on which "enum" value was chosen.
switch (authenticationMethodVariable.Value)
{
    case authenticationMethodVariable.Values.Forms: // Do something
        break;
    case authenticationMethodVariable.Values.Windows: // Do something
        break;
    case authenticationMethodVariable.Values.SSN: // Do something
        break;      
}

21
2018-01-08 15:52