CkH*_*CkH 4 c# extension-methods enums attributes
我有一个需要序列化为EDI格式的对象.对于这个例子,我们会说它是一辆汽车.汽车可能不是b/c选项随时间变化的最佳示例,但对于真实对象,Enums永远不会改变.
我有许多枚举,如下所示,应用了自定义属性.
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,
}
Run Code Online (Sandbox Code Playgroud)
通过扩展方法访问属性:
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();
}
Run Code Online (Sandbox Code Playgroud)
有一个自定义EDI序列化程序,它基于StringValue属性进行序列化,如下所示:
StringBuilder sb = new StringBuilder();
sb.Append(car.RoofStyle.GetStringValue());
sb.Append(car.TireSize.GetStringValue());
sb.Append(car.Model.GetStringValue());
...
Run Code Online (Sandbox Code Playgroud)
还有另一种方法可以从StringValue获取Enum Value以进行反序列化:
car.RoofStyle = Enums.GetCode<RoofStyle>(EDIString.Substring(4, 3))
Run Code Online (Sandbox Code Playgroud)
定义为:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
最后,对于UI,GetDisplayText()它用于显示用户友好的文本.
你怎么看?矫枉过正?有没有更好的办法?还是Goldie Locks(恰到好处)?
只是想在我将其永久地集成到我的个人框架之前获得反馈.谢谢.
您用于序列化的部分很好.反序列化部分写得很笨拙.主要的问题是你ToUpper()用来比较字符串,这很容易被打破(想想全球化).这样的比较应该用string.Compare,或者string.Equals重载,需要一个StringComparison.
另一件事是在反序列化期间反复执行这些查找会非常缓慢.如果你要序列化大量数据,这实际上可能非常明显.在这种情况下,您需要构建一个从StringValue枚举到枚举的映射- 将其抛入静态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(...);
}
}
Run Code Online (Sandbox Code Playgroud)
它不像"通用",但它的效率更高.如果您不喜欢字符串值的重复,则在单独的类中将代码提取为常量.
如果你真的需要它是完全通用的并适用于任何枚举,你总是可以在第一次转换时懒惰加载值的字典(使用你编写的扩展方法生成它).这样做非常简单:
static Dictionary<string, T> CreateEnumLookup<T>()
{
return Enum.GetValues(typeof(T)).ToDictionary(o => ((Enum)o).GetStringValue(),
o => (T)o);
}
Run Code Online (Sandbox Code Playgroud)
PS次要细节,但您可能需要考虑使用Attribute.GetCustomAttribute而不是MemberInfo.GetCustomAttributes如果您只希望有一个属性.当你只需要一个项目时,没有理由让所有阵列摆弄.