634 Stimmen

Assoziieren von Enums mit Strings in C#

Ich weiß, dass das Folgende nicht möglich ist, weil der Typ der Aufzählung ein int sein muss

enum GroupTypes
{
    TheGroup = "OEM",
    TheOtherGroup = "CMB"
}

In meiner Datenbank erhalte ich ein Feld mit unverständlichen Codes (die OEM y CMB s). Ich möchte dieses Feld zu einem enum oder etwas anderes Verständliches. Denn wenn das Ziel die Lesbarkeit ist, sollte die Lösung prägnant sein.

Welche anderen Möglichkeiten habe ich?

1 Stimmen

Mögliche Duplikate von Enum ToString

24 Stimmen

Ich bin mir nicht sicher, warum die meisten Antworten nicht einfach "const string" verwenden und stattdessen eigene Klassen erstellen.

2 Stimmen

Sie können zwar keine Zeichenketten verwenden, aber Sie können sehr wohl Zeichenketten verwenden. Das ist eine Option, wenn Sie Werte mit nur einem Buchstaben verwenden können.

4voto

Rolf Staflin Punkte 1672

Hier ist meine Ansicht dazu, mit C# 9.0 Syntax, um es sauber zu halten. Ich definiere eine Basisklasse für die Enums:

public class StringEnum
{
    protected StringEnum(string value) { Value = value; }
    public string Value { get; }
    public override string ToString() => Value;
}

Das Erstellen neuer Enum-Typen ist dann einfach und kompakt:

public class GroupTypes : StringEnum
{ 
    private GroupTypes(string value) : base(value) {}

    public static readonly GroupTypes TheGroup = new("OEM");
    public static readonly GroupTypes TheOtherGroup = new("CMB");
}

Verwenden Sie es so:

void Example(GroupTypes groupType)
{
    Console.WriteLine(groupType); // Will print "OEM" or "CMB"
    if (groupType == GroupTypes.TheGroup) { ... }
}

Sie können auch weitere Funktionen hinzufügen zu StringEnum die dann für alle Ihre Unterklassen zur Verfügung steht (z. B. durch Implementierung von IComparable und übergeordnet Equals y GetHashCode )

4voto

Roman M Punkte 331
public class DataType
{
    private readonly string value;
    private static readonly Dictionary<string, DataType> predefinedValues;

    public static readonly DataType Json = new DataType("json");
    public static readonly DataType Xml = new DataType("xml");
    public static readonly DataType Text = new DataType("text");
    public static readonly DataType Html = new DataType("html");
    public static readonly DataType Binary = new DataType("binary");

    static DataType()
    {
        predefinedValues = new Dictionary<string, DataType>();
        predefinedValues.Add(Json.Value, Json);
        predefinedValues.Add(Xml.Value, Xml);
        predefinedValues.Add(Text.Value, Text);
        predefinedValues.Add(Html.Value, Html);
        predefinedValues.Add(Binary.Value, Binary);
    }

    private DataType(string value)
    {
        this.value = value;
    }

    public static DataType Parse(string value)
    {
        var exception = new FormatException($"Invalid value for type {nameof(DataType)}");
        if (string.IsNullOrEmpty(value))
            throw exception;

        string key = value.ToLower();
        if (!predefinedValues.ContainsKey(key))
            throw exception;

        return predefinedValues[key];
    }

    public string Value
    {
        get { return value; }
    }
}

4voto

jhale Punkte 1710

Ich würde einfach ein Wörterbuch erstellen und den Code als Schlüssel verwenden.

Bearbeiten: Um die Bemerkung über die Durchführung einer Rückwärtssuche (Auffinden des Schlüssels) anzusprechen, wäre dies nicht sehr effizient. Wenn dies notwendig ist, würde ich eine neue Klasse schreiben, um es zu behandeln.

3voto

Claus Elmann Punkte 47

In VS 2015 können Sie nameof

public class LogCategory
{
    public static string Trace;
    public static string Debug;
    public static string Info;
    public static string Warning;
    public static string Error;
}

Verwendung:

Logger.Write("This is almost like an enum.", nameof(LogCategory.Info));

3voto

Lomithrani Punkte 1865

Nach der Antwort von @Even Mien habe ich versucht, ein bisschen weiter zu gehen und es generisch zu machen, ich scheine fast am Ziel zu sein, aber ein Fall sträubt sich noch und ich kann wahrscheinlich meinen Code ein bisschen vereinfachen.
Ich poste es hier, wenn jemand sehen, wie ich verbessern könnte und vor allem machen es funktioniert, da ich nicht zuweisen kann es von einer Zeichenfolge

Bisher habe ich die folgenden Ergebnisse:

        Console.WriteLine(TestEnum.Test1);//displays "TEST1"

        bool test = "TEST1" == TestEnum.Test1; //true

        var test2 = TestEnum.Test1; //is TestEnum and has value

        string test3 = TestEnum.Test1; //test3 = "TEST1"

        var test4 = TestEnum.Test1 == TestEnum.Test2; //false
         EnumType<TestEnum> test5 = "TEST1"; //works fine

        //TestEnum test5 = "string"; DOESN'T compile .... :(:(

Wo die Magie geschieht:

public abstract  class EnumType<T>  where T : EnumType<T>   
{

    public  string Value { get; set; }

    protected EnumType(string value)
    {
        Value = value;
    }

    public static implicit operator EnumType<T>(string s)
    {
        if (All.Any(dt => dt.Value == s))
        {
            Type t = typeof(T);

            ConstructorInfo ci = t.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic,null, new Type[] { typeof(string) }, null);

            return (T)ci.Invoke(new object[] {s});
        }
        else
        {
            return null;
        }
    }

    public static implicit operator string(EnumType<T> dt)
    {
        return dt?.Value;
    }

    public static bool operator ==(EnumType<T> ct1, EnumType<T> ct2)
    {
        return (string)ct1 == (string)ct2;
    }

    public static bool operator !=(EnumType<T> ct1, EnumType<T> ct2)
    {
        return !(ct1 == ct2);
    }

    public override bool Equals(object obj)
    {
        try
        {
            return (string)obj == Value;
        }
        catch
        {
            return false;
        }
    }

    public override int GetHashCode()
    {
        return Value.GetHashCode();
    }

    public static IEnumerable<T> All
     => typeof(T).GetProperties()
       .Where(p => p.PropertyType == typeof(T))
       .Select(x => (T)x.GetValue(null, null));

}

Ich muss dies dann nur noch für meine Enums deklarieren:

public class TestEnum : EnumType<TestEnum> 
{

    private TestEnum(string value) : base(value)
    {}

    public static TestEnum Test1 { get { return new TestEnum("TEST1"); } }
    public static TestEnum Test2 { get { return new TestEnum("TEST2"); } }
}

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