我的解决方案的基础是struct,它可以包装Enum 值并覆盖ToString()。
输入EnumWrapper:
public struct EnumWrapper
{
private readonly Enum e;
public EnumWrapper(Enum e) {
this.e = e;
}
public static implicit operator Enum(EnumWrapper wrapper) {
return wrapper.e;
}
public static explicit operator EnumWrapper(Enum e) {
return new EnumWrapper(e);
}
public override string ToString() {
return e.ToStringFriendly();
}
}
方法ToStringFriendly()被定义为Enum上的扩展方法:
using System.Text.RegularExpressions;
public static class _Extensions
{
public static string ToStringFriendly(this Enum e)
{
string s = e.ToString();
// enforce a charset: letters, numbers, and underscores
s = Regex.Replace(s, "[^A-Za-z0-9_]", "");
// separate numbers from letters
s = Regex.Replace(s, "([a-zA-Z])([0-9])", "$1 $2");
// separate letters from numbers
s = Regex.Replace(s, "([0-9])([a-zA-Z])", "$1 $2");
// space lowercases before uppercase (word boundary)
s = Regex.Replace(s, "([a-z])([A-Z])", "$1 $2");
// see that the nice pretty capitalized words are spaced left
s = Regex.Replace(s, "(?!^)([^ _])([A-Z][a-z]+)", "$1 $2");
// replace double underscores with colon-space delimiter
s = Regex.Replace(s, "__", ": ");
// finally replace single underscores with hyphens
s = Regex.Replace(s, "_", "-");
return s;
}
}
现在,例如,将任何 Enum 值添加到 ComboBox,
comboBox.Items.Add((EnumWrapper)MyEnum.SomeValue);
然后将其取出(当然是在空测试之后):
MyEnum myValue = (MyEnum)(Enum)(EnumWrapper)comboBox.SelectedItem;
就是这样。现在这种方法的优缺点是什么?
优点:
- 您可以(几乎)直接将枚举值传入和传出控件。只需在
EnumWrapper 之间来回投射。
- 这适用于所有 Pascal 大小写的
Enum 值以及一些特殊情况。一个例子可能是一个名为MyValue__DescriptionOf123_ENUMValue 的值,它来自ToStringFriendly(),作为“我的值:123-ENUM 值的描述”。
- 机制(
struct 和扩展方法)可以编写一次并隐藏起来。每个Enum 中没有额外的编码。这意味着它在上面 对于您没有编写的枚举 可以很好地工作,假设 Pascal 情况,这在 .NET 中是一个很好的假设。 注意:这就是为什么我会说this answer,尽管它很优雅,但并不是比我更好的解决方案,因为它要求您可以为每个Enum 添加一个TypeConverter 属性。
缺点:
- 这不支持自定义描述或多语言。例如,
Encoding.EBCDIC 之类的值将始终以“EBCDIC”的形式出现,并且不允许您手动输入“扩展二进制编码十进制交换码”,更不用说其他语言了。
未来工作
可以通过更改 ToStringFriendly() 来添加自定义描述和多语言支持,以便在去帕斯卡大小写之前对该值进行语言查找。
更多正则表达式的乐趣,请参阅this thread。