我知道下面是不可能的,因为枚举的类型必须是int
enum GroupTypes
{
TheGroup = "OEM",
TheOtherGroup = "CMB"
}
从我的数据库中,我得到了一个不全面的代码字段(OEM和CMBs)。我想让这个字段成为一个枚举或其他可以理解的东西。因为如果目标是可读性,解决方案就应该简洁。
我还有其他选择吗?
我知道下面是不可能的,因为枚举的类型必须是int
enum GroupTypes
{
TheGroup = "OEM",
TheOtherGroup = "CMB"
}
从我的数据库中,我得到了一个不全面的代码字段(OEM和CMBs)。我想让这个字段成为一个枚举或其他可以理解的东西。因为如果目标是可读性,解决方案就应该简洁。
我还有其他选择吗?
当前回答
下面是我对这个问题的看法,使用c# 9.0语法来保持整洁。我为枚举定义了一个基类:
public class StringEnum
{
protected StringEnum(string value) { Value = value; }
public string Value { get; }
public override string ToString() => Value;
}
创建新的枚举样式类型是简单而紧凑的:
public class GroupTypes : StringEnum
{
private GroupTypes(string value) : base(value) {}
public static readonly GroupTypes TheGroup = new("OEM");
public static readonly GroupTypes TheOtherGroup = new("CMB");
}
像这样使用它:
void Example(GroupTypes groupType)
{
Console.WriteLine(groupType); // Will print "OEM" or "CMB"
if (groupType == GroupTypes.TheGroup) { ... }
}
你也可以给StringEnum添加更多的功能,这样你的所有子类都可以使用(例如,实现IComparable和重写Equals和GetHashCode)
其他回答
我喜欢在类中使用属性而不是方法,因为它们看起来更像枚举。
下面是一个Logger的例子:
public class LogCategory
{
private LogCategory(string value) { Value = value; }
public string Value { get; private 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"); } }
public override string ToString()
{
return Value;
}
}
传入类型安全的字符串值作为参数:
public static void Write(string message, LogCategory logCategory)
{
var log = new LogEntry { Message = message };
Logger.Write(log, logCategory.Value);
}
用法:
Logger.Write("This is almost like an enum.", LogCategory.Info);
在@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"); } }
}
我想完全避免使用字符串字面量,而且我也不需要在项目描述中有空间。更重要的是,我想要有一种机制来检查所提供的字符串是否是一个有效的项目,所以我想出了这个解决方案:
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;
}
}
你可以很容易地做到。使用下面的代码。
enum GroupTypes
{
OEM,
CMB
};
然后,当您想获取每个枚举元素的字符串值时,只需使用下面的代码行。
String oemString = Enum.GetName(typeof(GroupTypes), GroupTypes.OEM);
我曾经成功地使用过这个方法,我也使用过一个常量类来保存字符串常量,两者都很好,但我倾向于这样做。
. 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抛出的橄榄枝。
希望它能帮助到一些人!