Associating enums with strings in C#

2019-01-02 16:54发布

I know the following is not possible because it has to be an int

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

From my database I get a field with incomprehensive codes (the OEM and CMB's). I would want to make this field into an enum or something else understandable. Because the target is readability the solution should be terse.
What other options do I have?

标签: c# .net
30条回答
回忆,回不去的记忆
2楼-- · 2019-01-02 17:04

Answer by Even:

public class LogCategory
{
 private LogCategory(string value) { Value = value; }

 public string Value { get; set; }

 public static LogCategory Trace { get { return new LogCategory("Trace"); } }
 public static LogCategory Debug { get { return new LogCategory("Debug"); } }
 public static LogCategory Info { get { return new LogCategory("Info"); } }
 public static LogCategory Warning { get { return new LogCategory("Warning"); } }
 public static LogCategory Error { get { return new LogCategory("Error"); } }
}

Just wanted to add a way how to mimic switch with class based enums:

public void Foo(LogCategory logCategory){    

  var @switch = new Dictionary<LogCategory, Action>{
    {LogCategory.Trace, ()=>Console.Writeline("Trace selected!")},
    {LogCategory.Debug, ()=>Console.Writeline("Debug selected!")},
    {LogCategory.Error, ()=>Console.Writeline("Error selected!")}};

   //will print one of the line based on passed argument
  @switch[logCategory]();
}
查看更多
刘海飞了
3楼-- · 2019-01-02 17:05

Have you considered a lookup table using a Dictionary?

enum GroupTypes
{
    TheGroup,
    TheOtherGroup
}

Dictionary<string, GroupTypes> GroupTypeLookup = new Dictionary<string, GroupTypes>();
// initialize lookup table:
GroupTypeLookup.Add("OEM", TheGroup);
GroupTypeLookup.Add("CMB", TheOtherGroup);

You can then use GroupTypeLookup.TryGetValue() to look up a string when you read it.

查看更多
其实,你不懂
4楼-- · 2019-01-02 17:05

You can use two enums. One for the database and the other for readability.

You just need to make sure they stay in sync, which seems like a small cost. You don't have to set the values, just set the positions the same, but setting the values makes it very clear the two enums are related and prevents errors from rearranging the enum members. And a comment lets the maintenance crew know these are related and must be kept in sync.

// keep in sync with GroupTypes
public enum GroupTypeCodes
{
    OEM,
    CMB
}

// keep in sync with GroupTypesCodes
public enum GroupTypes
{
    TheGroup = GroupTypeCodes.OEM,
    TheOtherGroup = GroupTypeCodes.CMB
}

To use it you just convert to the code first:

GroupTypes myGroupType = GroupTypes.TheGroup;
string valueToSaveIntoDatabase = ((GroupTypeCodes)myGroupType).ToString();

Then if you want to make it even more convenient you can add an extension function that only works for this type of enum:

public static string ToString(this GroupTypes source)
{
    return ((GroupTypeCodes)source).ToString();
}

and you can then just do:

GroupTypes myGroupType = GroupTypes.TheGroup;
string valueToSaveIntoDatabase = myGroupType.ToString();
查看更多
有味是清欢
5楼-- · 2019-01-02 17:06

You could also use the extension model:

public enum MyEnum
{
    [Description("String 1")]
    V1= 1,
    [Description("String 2")]
    V2= 2
} 

Your Extension Class

public static class MyEnumExtensions
{
    public static string ToDescriptionString(this MyEnum val)
    {
        DescriptionAttribute[] attributes = (DescriptionAttribute[])val
           .GetType()
           .GetField(val.ToString())
           .GetCustomAttributes(typeof(DescriptionAttribute), false);
        return attributes.Length > 0 ? attributes[0].Description : string.Empty;
    }
} 

usage:

MyEnum myLocal = MyEnum.V1;
print(myLocal.ToDescriptionString());
查看更多
皆成旧梦
6楼-- · 2019-01-02 17:06

I even implemented a few enums as suggested by @Even (via class X and public static X members), just to find out later that these days, starting .Net 4.5, there's the right ToString() method.

Now I'm reimplementing everything back to enums.

查看更多
人间绝色
7楼-- · 2019-01-02 17:07

You can add attributes to the items in the enumeration and then use reflection to get the values from the attributes.

You would have to use the "field" specifier to apply the attributes, like so:

enum GroupTypes
{
    [field:Description("OEM")]
    TheGroup,

    [field:Description("CMB")]
    TheOtherGroup
}

You would then reflect on the static fields of the type of the enum (in this case GroupTypes) and get the DescriptionAttribute for the value you were looking for using reflection:

public static DescriptionAttribute GetEnumDescriptionAttribute<T>(
    this T value) where T : struct
{
    // The type of the enum, it will be reused.
    Type type = typeof(T);

    // If T is not an enum, get out.
    if (!type.IsEnum) 
        throw new InvalidOperationException(
            "The type parameter T must be an enum type.");

    // If the value isn't defined throw an exception.
    if (!Enum.IsDefined(type, value))
        throw new InvalidEnumArgumentException(
            "value", Convert.ToInt32(value), type);

    // Get the static field for the value.
    FieldInfo fi = type.GetField(value.ToString(), 
        BindingFlags.Static | BindingFlags.Public);

    // Get the description attribute, if there is one.
    return fi.GetCustomAttributes(typeof(DescriptionAttribute), true).
        Cast<DescriptionAttribute>().SingleOrDefault();
}

I opted to return the DescriptionAttribute itself above, in the event that you want to be able to determine whether or not the attribute is even applied.

查看更多
登录 后发表回答