954 Stimmen

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" benötige, wenn ich nach AuthenticationMethod.FORMS frage, und nicht die ID 1.

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

Zunächst 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 zu 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 erhalten. Ich kann ihn dann wie folgt verwenden:

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

Okay, das funktioniert alles prima, aber ich finde es eine Menge Arbeit. Ich habe mich gefragt, ob es eine bessere Lösung für dieses Problem gibt.

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

5 Stimmen

Auch wenn Sie das vielleicht langatmig finden, so ist es doch ein ziemlich flexibler Weg, um andere Dinge zu erledigen. Wie einer meiner Kollegen bemerkte, könnte dies in vielen Fällen verwendet werden, um Enum Helpers zu ersetzen, die Datenbankcodes auf Enum-Werte usw. abbilden.

3 Stimmen

Es handelt sich um eine "Aufzählung", nicht um einen "Enumerator".

29 Stimmen

MSDN empfiehlt, Attributklassen mit dem Suffix "Attribute" zu versehen. Also "Klasse StringValueAttribute" ;)

4voto

Pablo Retyk Punkte 5552

Option 1:

public sealed class FormsAuth
{
     public override string ToString{return "Forms Authtentication";}
}
public sealed class WindowsAuth
{
     public override string ToString{return "Windows Authtentication";}
}

public sealed class SsoAuth
{
     public override string ToString{return "SSO";}
}

und dann

object auth = new SsoAuth(); //or whatever

//...
//...
// blablabla

DoSomethingWithTheAuth(auth.ToString());

Option 2:

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

public class MyClass
{
    private Dictionary<AuthenticationMethod, String> map = new Dictionary<AuthenticationMethod, String>();
    public MyClass()
    {
         map.Add(AuthenticationMethod.FORMS,"Forms Authentication");
         map.Add(AuthenticationMethod.WINDOWSAUTHENTICATION ,"Windows Authentication");
         map.Add(AuthenticationMethod.SINGLESIGNON ,"SSo Authentication");
    }
}

4voto

Sith2021 Punkte 2514

Für mich ist der pragmatische Ansatz Klasse in Klasse, Beispiel:

public class MSEModel
{
    class WITS
    {
        public const string DATE = "5005";
        public const string TIME = "5006";
        public const string MD = "5008";
        public const string ROP = "5075";
        public const string WOB = "5073";
        public const string RPM = "7001";
... 
    }

3voto

Russ Punkte 31

Hier ist eine weitere Möglichkeit, die Aufgabe der Verknüpfung von Strings mit Enums zu bewältigen:

struct DATABASE {
    public enum enums {NOTCONNECTED, CONNECTED, ERROR}
    static List<string> strings =
        new List<string>() {"Not Connected", "Connected", "Error"};

    public string GetString(DATABASE.enums value) {
        return strings[(int)value];
    }
}

Diese Methode wird wie folgt aufgerufen:

public FormMain() {
    DATABASE dbEnum;

    string enumName = dbEnum.GetString(DATABASE.enums.NOTCONNECTED);
}

Sie können zusammengehörige Enums in einer eigenen Struktur gruppieren. Da diese Methode den Enum-Typ verwendet, können Sie Intellisense verwenden, um die Liste der Enums anzuzeigen, wenn Sie die GetString() anrufen.

Sie können optional den neuen Operator auf der DATABASE Struktur. Wird sie nicht verwendet, bedeutet dies, dass die Strings List wird nicht vor dem ersten GetString() Anruf getätigt wird.

3voto

chrispepper1989 Punkte 1918

Eine Menge von großen Antworten hier, aber in meinem Fall nicht lösen, was ich wollte aus einem "String-Enum", die war:

  1. Verwendbar in einer switch-Anweisung z.B. switch(myEnum)
  2. Kann in Funktionsparametern verwendet werden, z. B. foo(myEnum type)
  3. Kann referenziert werden z.B. myEnum.FirstElement
  4. Ich kann Strings verwenden, z. B. foo("FirstElement") == foo(myEnum.FirstElement)

1,2 & 4 können eigentlich mit einem C# Typedef eines Strings gelöst werden (da Strings in C# umschaltbar sind)

3 kann durch statische Konstanten gelöst werden. Wenn Sie also die gleichen Bedürfnisse haben, ist dies der einfachste Ansatz:

public sealed class Types
{

    private readonly String name;

    private Types(String name)
    {
        this.name = name;

    }

    public override String ToString()
    {
        return name;
    }

    public static implicit operator Types(string str)
    {
        return new Types(str);

    }
    public static implicit operator string(Types str)
    {
        return str.ToString();
    }

    #region enum

    public const string DataType = "Data";
    public const string ImageType = "Image";
    public const string Folder = "Folder";
    #endregion

}

Dies ermöglicht zum Beispiel:

    public TypeArgs(Types SelectedType)
    {
        Types SelectedType = SelectedType
    }

y

public TypeObject CreateType(Types type)
    {
        switch (type)
        {

            case Types.ImageType:
              //
                break;

            case Types.DataType:
             //
                break;

        }
    }

Dabei kann CreateType mit einer Zeichenkette oder einem Typ aufgerufen werden. Der Nachteil ist jedoch, dass jede Zeichenkette automatisch eine gültige Aufzählung ist Dies könnte geändert werden, aber dann würde es eine Art von Init-Funktion erfordern ... oder möglicherweise machen sie explizit Cast intern?

Wenn ein int-Wert für Sie wichtig wäre (vielleicht für die Vergleichsgeschwindigkeit), könnten Sie podría einige Ideen aus der fantastischen Antwort von Jakub Šturc nutzen und etwas bit verrückt, das ist mein Versuch:

    public sealed class Types
{
    private static readonly Dictionary<string, Types> strInstance = new Dictionary<string, Types>();
    private static readonly Dictionary<int, Types> intInstance = new Dictionary<int, Types>();

    private readonly String name;
    private static int layerTypeCount = 0;
    private int value;
    private Types(String name)
    {
        this.name = name;
        value = layerTypeCount++;
        strInstance[name] = this;
        intInstance[value] = this;
    }

    public override String ToString()
    {
        return name;
    }

    public static implicit operator Types(int val)
    {
        Types result;
        if (intInstance.TryGetValue(val, out result))
            return result;
        else
            throw new InvalidCastException();
    }

    public static implicit operator Types(string str)
    {
        Types result;
        if (strInstance.TryGetValue(str, out result))
        {
            return result;
        }
        else
        {
            result = new Types(str);
            return result;
        }

    }
    public static implicit operator string(Types str)
    {
        return str.ToString();
    }

    public static bool operator ==(Types a, Types b)
    {
        return a.value == b.value;
    }
    public static bool operator !=(Types a, Types b)
    {
        return a.value != b.value;
    }

    #region enum

    public const string DataType = "Data";
    public const string ImageType = "Image";

    #endregion

}

aber natürlich wäre "Typen bob = 4;" bedeutungslos, es sei denn, man hätte sie vorher initialisiert, was den Sinn des Ganzen irgendwie zunichte machen würde...

Aber theoretisch wäre TypA == TypB schneller...

3voto

WHol Punkte 2098

Wenn ich Sie richtig verstehe, können Sie einfach .ToString() verwenden, um den Namen der Enum aus dem Wert abzurufen (vorausgesetzt, es ist bereits als Enum gecastet); Wenn Sie die nackte int hatte (sagen wir aus einer Datenbank oder etwas), können Sie zuerst Cast es auf die Enum. Beide Methoden unten werden Sie den Enum-Namen erhalten.

AuthenticationMethod myCurrentSetting = AuthenticationMethod.FORMS;
Console.WriteLine(myCurrentSetting); // Prints: FORMS
string name = Enum.GetNames(typeof(AuthenticationMethod))[(int)myCurrentSetting-1];
Console.WriteLine(name); // Prints: FORMS

Beachten Sie jedoch, dass die zweite Technik davon ausgeht, dass Sie Ints verwenden und Ihr Index auf 1 basiert (nicht auf 0). Die Funktion GetNames ist auch ziemlich schwer im Vergleich, Sie erzeugen ein ganzes Array jedes Mal, wenn sie aufgerufen wird. Wie Sie in der ersten Technik sehen können, wird .ToString() tatsächlich implizit aufgerufen. Beides ist natürlich bereits in den Antworten erwähnt, ich versuche nur, die Unterschiede zwischen ihnen zu verdeutlichen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X