我知道下面是不可能的,因为枚举的类型必须是int

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

从我的数据库中,我得到了一个不全面的代码字段(OEM和CMBs)。我想让这个字段成为一个枚举或其他可以理解的东西。因为如果目标是可读性,解决方案就应该简洁。

我还有其他选择吗?


当前回答

Glennular Extension方法的一个小调整,所以你可以在其他东西上使用扩展,而不仅仅是ENUM的;

using System;
using System.ComponentModel;
namespace Extensions {
    public static class T_Extensions {
        /// <summary>
        /// Gets the Description Attribute Value
        /// </summary>
        /// <typeparam name="T">Entity Type</typeparam>
        /// <param name="val">Variable</param>
        /// <returns>The value of the Description Attribute or an Empty String</returns>
        public static string Description<T>(this T t) {
            DescriptionAttribute[] attributes = (DescriptionAttribute[])t.GetType().GetField(t.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
            return attributes.Length > 0 ? attributes[0].Description : string.Empty;
        }
    }
}

或者使用Linq

using System;
using System.ComponentModel;
using System.Linq;

namespace Extensions {


public static class T_Extensions {
        public static string Description<T>(this T t) =>
            ((DescriptionAttribute[])t
            ?.GetType()
            ?.GetField(t?.ToString())
            ?.GetCustomAttributes(typeof(DescriptionAttribute), false))
            ?.Select(a => a?.Description)
            ?.FirstOrDefault() 
            ?? string.Empty;  
    }
}

其他回答

您可以使用两个枚举。一个用于数据库,另一个用于可读性。

你只需要确保它们保持同步,这似乎是一个小成本。 你不必设置值,只是设置相同的位置,但设置值可以非常清楚地表明两个枚举是相关的,并防止错误重新排列枚举成员。注释让维护人员知道这些是相关的,必须保持同步。

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

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

要使用它,你只需要先转换为代码:

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

然后,如果你想让它更方便,你可以添加一个扩展函数,只适用于这种类型的枚举:

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

然后你可以这样做:

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

. net Core 3.0/ c# 8.0(如果你的工作环境允许你升级你的项目)新增了一个简短的switch语句,看起来有点枚举。在一天结束的时候,这和我们多年来一直在使用的无聊的开关语句是一样的。

这里唯一真正的区别是switch语句得到了一个新的suit。

public static RGBColor FromRainbow(Rainbow colorBand) =>
colorBand switch
{
    Rainbow.Red    => new RGBColor(0xFF, 0x00, 0x00),
    Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),
    Rainbow.Yellow => new RGBColor(0xFF, 0xFF, 0x00),
    Rainbow.Green  => new RGBColor(0x00, 0xFF, 0x00),
    Rainbow.Blue   => new RGBColor(0x00, 0x00, 0xFF),
    Rainbow.Indigo => new RGBColor(0x4B, 0x00, 0x82),
    Rainbow.Violet => new RGBColor(0x94, 0x00, 0xD3),
    _              => throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)),
};

你会注意到上面我从这里复制的代码,实际上是使用一个枚举作为参数。

这并不是您想要的(相信我,我早就想要类似OP要求的东西了),但我实际上觉得这是MS. JMO抛出的橄榄枝。

希望它能帮助到一些人!

为你的DB创建第二个枚举,包含以下内容:

enum DBGroupTypes
{
    OEM = 0,
    CMB = 1
}

现在,您可以使用Enum。解析以从字符串“OEM”和“CMB”中检索正确的DBGroupTypes值。然后,您可以将这些值转换为int,并从您希望在模型中进一步使用的正确枚举中检索正确的值。

在@Even Mien的回答之后,我试着走得更远一点,使它通用,我似乎几乎在那里,但有一种情况仍然抗拒,我可能可以简化我的代码一点。 我张贴在这里,如果有人看到我可以改进,特别是使它工作,因为我不能从字符串赋值

到目前为止,我有以下结果:

        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 .... :(:(

奇迹发生的地方:

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));



}

我只需要为我的枚举声明这个:

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"); } }
}

在VS 2015中,你可以使用nameof

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

用法:

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