Custom Enum Parse
我有一个枚举如下:
1 | public enum MyEnum { One, Two, Three} |
我想将一些字符串削减到上面的枚举,例如,下面的字符串将被解析为myenum。
1 | "Two","TWO","Second","2" |
我知道我可以维护一个映射函数来完成这项工作。但是,我只想找到一种更好的方法,例如重写enum.parse函数或类似的方法。我试图使用IConvertable,但似乎不可能。有什么想法吗?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | [AttributeUsage(AttributeTargets.Field, AllowMultiple = true)] public class NameAttribute : Attribute { public readonly string[] Names; public NameAttribute(string name) { if (name == null) { throw new ArgumentNullException(); } Names = new[] { name }; } public NameAttribute(params string[] names) { if (names == null || names.Any(x => x == null)) { throw new ArgumentNullException(); } Names = names; } } public static class ParseEnum { public static TEnum Parse<TEnum>(string value) where TEnum : struct { return ParseEnumImpl<TEnum>.Values[value]; } public static bool TryParse<TEnum>(string value, out TEnum result) where TEnum : struct { return ParseEnumImpl<TEnum>.Values.TryGetValue(value, out result); } private static class ParseEnumImpl<TEnum> where TEnum : struct { public static readonly Dictionary<string, TEnum> Values = new Dictionary<string,TEnum>(); static ParseEnumImpl() { var nameAttributes = typeof(TEnum) .GetFields() .Select(x => new { Value = x, Names = x.GetCustomAttributes(typeof(NameAttribute), false) .Cast<NameAttribute>() }); var degrouped = nameAttributes.SelectMany( x => x.Names.SelectMany(y => y.Names), (x, y) => new { Value = x.Value, Name = y }); Values = degrouped.ToDictionary( x => x.Name, x => (TEnum)x.Value.GetValue(null)); } } } |
然后可以(注意
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public enum TestEnum { [Name("1")] [Name("Foo")] [Name("F")] [Name("XF","YF")] Foo = 1, [Name("2")] [Name("Bar")] [Name("B")] [Name("XB","YB")] Bar = 2 } |
和
1 2 3 | TestEnum r1 = ParseEnum.Parse<TestEnum>("XF"); TestEnum r2; bool r3 = ParseEnum.TryParse<TestEnum>("YB", out r2); |
注意使用内部类(
最好的方法就是存储一个带有映射的
1 2 3 4 5 6 | static Dictionary<string, string> _mappings = new Dictionary<string, string> { {"Two","Two" }, {"Second","Two" }, {"2","Two" } }; |
然后您将其称为
1 2 |
通常,我更喜欢简单的解决方案,因为它们比"重写
但我们可以通过使用
1 2 3 4 5 6 | static Dictionary<string, MyEnum> _mappings = new Dictionary<string, MyEnum> { {"Two", MyEnum.Two }, {"Second", MyEnum.Two }, {"2", MyEnum.Two } }; |
现在要获取枚举:
1 | MyEnum myEnumb = _mappings[str]; |
后一种方法也提高了性能,因为我们避免了
您试图分析两种不同的情况:
如果这两种情况是输入中唯一的情况,您可以简单地使用Enum.Tryparse方法(String、Boolean、Tenum)尝试以不区分大小写的方式分析文本:
1 2 3 4 5 | MyEnum output; if (Enum.TryParseEnum(input,true,out output)) { // Process succesfull value } |
从文档示例中,您可以看到
至于解析
事实上,如果数据来自外部文件,这是ETL问题,而不是解析问题。在这种情况下,典型的解决方案是创建查找表,将输入映射到可识别的输出,并在解析之前用查找值替换输入。