- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个对象需要序列化为 EDI 格式。对于这个例子,我们假设它是一辆汽车。汽车可能不是 b/c 选项随时间变化的最佳示例,但对于真实对象,枚举永远不会改变。
我有很多像下面这样的应用了自定义属性的枚举。
public enum RoofStyle
{
[DisplayText("Glass Top")]
[StringValue("GTR")]
Glass,
[DisplayText("Convertible Soft Top")]
[StringValue("CST")]
ConvertibleSoft,
[DisplayText("Hard Top")]
[StringValue("HT ")]
HardTop,
[DisplayText("Targa Top")]
[StringValue("TT ")]
Targa,
}
通过扩展方法访问属性:
public static string GetStringValue(this Enum value)
{
// Get the type
Type type = value.GetType();
// Get fieldinfo for this type
FieldInfo fieldInfo = type.GetField(value.ToString());
// Get the stringvalue attributes
StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes(
typeof(StringValueAttribute), false) as StringValueAttribute[];
// Return the first if there was a match.
return attribs.Length > 0 ? attribs[0].StringValue : null;
}
public static string GetDisplayText(this Enum value)
{
// Get the type
Type type = value.GetType();
// Get fieldinfo for this type
FieldInfo fieldInfo = type.GetField(value.ToString());
// Get the DisplayText attributes
DisplayTextAttribute[] attribs = fieldInfo.GetCustomAttributes(
typeof(DisplayTextAttribute), false) as DisplayTextAttribute[];
// Return the first if there was a match.
return attribs.Length > 0 ? attribs[0].DisplayText : value.ToString();
}
有一个自定义 EDI 序列化程序,它基于 StringValue 属性进行序列化,如下所示:
StringBuilder sb = new StringBuilder();
sb.Append(car.RoofStyle.GetStringValue());
sb.Append(car.TireSize.GetStringValue());
sb.Append(car.Model.GetStringValue());
...
还有一种方法可以从StringValue中获取Enum值进行反序列化:
car.RoofStyle = Enums.GetCode<RoofStyle>(EDIString.Substring(4, 3))
定义为:
public static class Enums
{
public static T GetCode<T>(string value)
{
foreach (object o in System.Enum.GetValues(typeof(T)))
{
if (((Enum)o).GetStringValue() == value.ToUpper())
return (T)o;
}
throw new ArgumentException("No code exists for type " + typeof(T).ToString() + " corresponding to value of " + value);
}
}
最后,对于 UI,GetDisplayText()
用于显示用户友好的文本。
你怎么看?矫枉过正?有没有更好的办法?还是 Goldie Locks(恰到好处)?
只是想在将其永久集成到我的个人框架之前获得反馈。谢谢。
最佳答案
您用来序列化的部分没问题。反序列化部分写得很别扭。主要问题是您使用的是 ToUpper()
比较容易损坏的字符串(想想全局化)。这种比较应该用 string.Compare
来完成。相反,或者 string.Equals overload这需要 StringComparison
.
另一件事是在反序列化过程中一次又一次地执行这些查找会非常慢。如果您正在序列化大量数据,这实际上可能会非常明显。在这种情况下,您需要从 StringValue
构建 map 到枚举本身 - 将其放入静态 Dictionary<string, RoofStyle>
并将其用作往返的查找。换句话说:
public static class Enums
{
private static Dictionary<string, RoofStyle> roofStyles =
new Dictionary<string, RoofStyle>()
{
{ "GTR", RoofStyle.Glass },
{ "CST", RoofStyle.ConvertibleSoft },
{ "HT ", RoofStyle.HardTop },
{ "TT ", RoofStyle.TargaTop }
}
public static RoofStyle GetRoofStyle(string code)
{
RoofStyle result;
if (roofStyles.TryGetValue(code, out result))
return result;
throw new ArgumentException(...);
}
}
它不是那么“通用”,但效率更高。如果您不喜欢字符串值的重复,则将代码提取为单独类中的常量。
如果你真的需要它是完全通用的并且适用于任何枚举,你总是可以在第一次完成转换时延迟加载值字典(使用你编写的扩展方法生成它)。这样做非常简单:
static Dictionary<string, T> CreateEnumLookup<T>()
{
return Enum.GetValues(typeof(T)).ToDictionary(o => ((Enum)o).GetStringValue(),
o => (T)o);
}
附言次要细节,但您可能要考虑使用 Attribute.GetCustomAttribute
而不是 MemberInfo.GetCustomAttributes
如果您只希望有一个属性。当您只需要一项时,没有理由摆弄所有数组。
关于c# - 扩展枚举,矫枉过正?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3015893/
我是一名优秀的程序员,十分优秀!