我知道下面是不可能的,因为枚举的类型必须是int
enum GroupTypes
{
TheGroup = "OEM",
TheOtherGroup = "CMB"
}
从我的数据库中,我得到了一个不全面的代码字段(OEM和CMBs)。我想让这个字段成为一个枚举或其他可以理解的东西。因为如果目标是可读性,解决方案就应该简洁。
我还有其他选择吗?
我知道下面是不可能的,因为枚举的类型必须是int
enum GroupTypes
{
TheGroup = "OEM",
TheOtherGroup = "CMB"
}
从我的数据库中,我得到了一个不全面的代码字段(OEM和CMBs)。我想让这个字段成为一个枚举或其他可以理解的东西。因为如果目标是可读性,解决方案就应该简洁。
我还有其他选择吗?
当前回答
在@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"); } }
}
其他回答
我的第一个问题-你有访问数据库本身的权限吗?这应该在数据库中规范化,否则,任何解决方案都将容易出错。根据我的经验,充满“OEM”和“CMB”的数据字段往往会随着时间的推移混合“OEM”和其他“垃圾数据”....如果可以规范化它,就可以使用包含元素的表中的键作为Enum,这样就完成了,结构更加简洁。
如果这是不可用的,我将使你的Enum,并使一个类来解析你的字符串为你的Enum。这至少会让您在处理非标准条目时具有一定的灵活性,在捕获或处理错误时也比使用enumeration . parse /Reflection/etc等方法灵活得多。字典可以工作,但如果你遇到大小写问题,可能会崩溃。
我建议你写一个类,这样你就可以:
// I renamed this to GroupType, since it sounds like each element has a single type...
GroupType theType = GroupTypeParser.GetGroupType(theDBString);
这样可以保留大部分的可读性,而不必更改DB。
如果我理解正确,你需要一个从字符串到enum的转换:
enum GroupTypes {
Unknown = 0,
OEM = 1,
CMB = 2
}
static GroupTypes StrToEnum(string str){
GroupTypes g = GroupTypes.Unknown;
try {
object o = Enum.Parse(typeof(GroupTypes), str, true);
g = (GroupTypes)(o ?? 0);
} catch {
}
return g;
}
// then use it like this
GroupTypes g1 = StrToEnum("OEM");
GroupTypes g2 = StrToEnum("bad value");
如果您愿意,可以使用枚举类型的泛型使其更加花哨。
我想完全避免使用字符串字面量,而且我也不需要在项目描述中有空间。更重要的是,我想要有一种机制来检查所提供的字符串是否是一个有效的项目,所以我想出了这个解决方案:
public class Seasons
{
public static string Spring { get; }
public static string Summer { get; }
public static string Fall { get; }
public static string Winter { get; }
public static bool IsValid(string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
{
return false;
}
try
{
return typeof(Seasons).GetProperty(propertyName) != null;
}
catch
{
return false;
}
}
}
它是这样工作的:
void Main()
{
string s = nameof(Seasons.Fall);
Console.WriteLine($"Fall is valid: {Seasons.IsValid(s)}"); // true
s = "WrongSeason";
Console.WriteLine($"WrongSeason is valid: {Seasons.IsValid(s)}"); // false
}
我尝试将IsValid()重构为基类并使用反射来读取类型(MethodBase.GetCurrentMethod(). declaringtype),但由于我希望它是静态的,所以它返回基类类型,而不是继承的类型。你的补救措施将是非常欢迎的!这就是我想要达到的目标:
public class Seasons : ConstantStringsBase
{
// ... same
}
public class ConstantStringsBase
{
public static bool IsValid(string propertyName)
{
return MethodBase.GetCurrentMethod().DeclaringType.GetProperty(propertyName) != null;
}
}
您可以使用两个枚举。一个用于数据库,另一个用于可读性。
你只需要确保它们保持同步,这似乎是一个小成本。 你不必设置值,只是设置相同的位置,但设置值可以非常清楚地表明两个枚举是相关的,并防止错误重新排列枚举成员。注释让维护人员知道这些是相关的,必须保持同步。
// 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();
你也可以使用扩展模型:
public enum MyEnum
{
[Description("String 1")]
V1= 1,
[Description("String 2")]
V2= 2
}
你的扩展类
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;
}
}
用法:
MyEnum myLocal = MyEnum.V1;
print(myLocal.ToDescriptionString());