convert an enum to another type of enum
我有一个枚举,例如"
我的问题是,如何快速而漂亮地写一些东西,将它们从枚举转换为我的枚举?
给定
1 |
如果您的意思是数值,您通常可以强制转换:
1 | Enum2 value2 = (Enum2)value; |
(对于强制转换,您可能希望使用
当使用Nate建议的两种转换方法时,使用扩展方法的效果相当好:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public static class TheirGenderExtensions { public static MyGender ToMyGender(this TheirGender value) { // insert switch statement here } } public static class MyGenderExtensions { public static TheirGender ToTheirGender(this MyGender value) { // insert switch statement here } } |
显然,如果不想使用单独的类,就不需要使用单独的类。我的首选是按应用于的类/结构/枚举对扩展方法进行分组。
只需将一个强制转换为int,然后将其强制转换为另一个枚举(考虑到您希望基于值完成映射):
1 | Gender2 gender2 = (Gender2)((int)gender1); |
为了彻底起见,我通常创建一对函数,一个接受枚举1并返回枚举2,另一个接受枚举2并返回枚举1。每个都包含一个case语句,将输入映射到输出,默认case抛出一个异常,并显示一条消息,抱怨意外的值。
在这个特定的例子中,您可以利用这样一个事实:男性和女性的整数值是相同的,但是我会避免这种情况,因为如果将来两个枚举中的任何一个发生变化,它都是黑客的,并且会受到破坏。
如果我们有:
1 2 3 4 5 6 | enum Gender { M = 0, F = 1, U = 2 } |
和
1 2 3 4 5 6 | enum Gender2 { Male = 0, Female = 1, Unknown = 2 } |
我们可以安全地做到
1 2 | var gender = Gender.M; var gender2 = (Gender2)(int)gender; |
甚至
1 | var enumOfGender2Type = (Gender2)0; |
如果要覆盖"="符号右侧的枚举值比左侧的枚举值多的情况,则必须编写自己的方法/字典来覆盖其他人建议的方法/字典。
您可以编写一个这样的简单的通用扩展方法
1 2 3 4 5 6 7 8 9 10 | public static T ConvertTo<T>(this object value) where T : struct,IConvertible { var sourceType = value.GetType(); if (!sourceType.IsEnum) throw new ArgumentException("Source type is not enum"); if (!typeof(T).IsEnum) throw new ArgumentException("Destination type is not enum"); return (T)Enum.Parse(typeof(T), value.ToString()); } |
您可以编写如下简单函数:
1 2 3 4 5 6 7 8 9 10 11 12 | public static MyGender ConvertTo(TheirGender theirGender) { switch(theirGender) { case TheirGender.Male: break;//return male case TheirGender.Female: break;//return female case TheirGender.Unknown: break;//return whatever } } |
如果有人感兴趣,这里有一个扩展方法版本
1 2 3 4 5 6 7 | public static TEnum ConvertEnum<TEnum >(this Enum source) { return (TEnum)Enum.Parse(typeof(TEnum), source.ToString(), true); } // Usage NewEnumType newEnum = oldEnumVar.ConvertEnum<NewEnumType>(); |
前一段时间我编写了一套扩展方法,它适用于几种不同类型的
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 | public static tEnum SetFlags<tEnum>(this Enum e, tEnum flags, bool set, bool typeCheck = true) where tEnum : IComparable { if (typeCheck) { if (e.GetType() != flags.GetType()) throw new ArgumentException("Argument is not the same type as this instance.","flags"); } var flagsUnderlyingType = Enum.GetUnderlyingType(typeof(tEnum)); var firstNum = Convert.ToUInt32(e); var secondNum = Convert.ToUInt32(flags); if (set) firstNum |= secondNum; else firstNum &= ~secondNum; var newValue = (tEnum)Convert.ChangeType(firstNum, flagsUnderlyingType); if (!typeCheck) { var values = Enum.GetValues(typeof(tEnum)); var lastValue = (tEnum)values.GetValue(values.Length - 1); if (newValue.CompareTo(lastValue) > 0) return lastValue; } return newValue; } |
从那里可以添加其他更具体的扩展方法。
1 2 3 4 5 6 7 8 9 | public static tEnum AddFlags<tEnum>(this Enum e, tEnum flags) where tEnum : IComparable { SetFlags(e, flags, true); } public static tEnum RemoveFlags<tEnum>(this Enum e, tEnum flags) where tEnum : IComparable { SetFlags(e, flags, false); } |
这一个会像你想做的那样改变
1 2 3 4 | public static tEnum ChangeType<tEnum>(this Enum e) where tEnum : IComparable { return SetFlags(e, default(tEnum), true, false); } |
不过,请注意,您可以使用此方法在任何
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public enum Turtle { None = 0, Pink, Green, Blue, Black, Yellow } [Flags] public enum WriteAccess : short { None = 0, Read = 1, Write = 2, ReadWrite = 3 } static void Main(string[] args) { WriteAccess access = WriteAccess.ReadWrite; Turtle turtle = access.ChangeType<Turtle>(); } |
变量
但是,使用此方法可以安全地避免未定义的
1 2 3 4 5 | static void Main(string[] args) { Turtle turtle = Turtle.Yellow; WriteAccess access = turtle.ChangeType<WriteAccess>(); } |
在这种情况下,
将
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 | public enum Letters { None = 0, A, B, C, D, E, F, G, H } [Flags] public enum Flavors { None = 0, Cherry = 1, Grape = 2, Orange = 4, Peach = 8 } static void Main(string[] args) { Flavors flavors = Flavors.Peach; Letters letters = flavors.ChangeType<Letters>(); } |
在这种情况下,由于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public static TEnum ConvertByName<TEnum>(this Enum source, bool ignoreCase = false) where TEnum : struct { // if limited by lack of generic enum constraint if (!typeof(TEnum).IsEnum) { throw new InvalidOperationException("enumeration type required."); } TEnum result; if (!Enum.TryParse(source.ToString(), ignoreCase, out result)) { throw new Exception("conversion failure."); } return result; } |
根据上面贾斯汀的回答,我想到了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /// <summary> /// Converts Enum Value to different Enum Value (by Value Name) See https://stackoverflow.com/a/31993512/6500501. /// </summary> /// <typeparam name="TEnum">The type of the enum to convert to.</typeparam> /// <param name="source">The source enum to convert from.</param> /// <returns></returns> /// <exception cref="InvalidOperationException"></exception> public static TEnum ConvertTo<TEnum>(this Enum source) { try { return (TEnum) Enum.Parse(typeof(TEnum), source.ToString(), ignoreCase: true); } catch (ArgumentException aex) { throw new InvalidOperationException ( $"Could not convert {source.GetType().ToString()} [{source.ToString()}] to {typeof(TEnum).ToString()}", aex ); } } |
我知道这是一个古老的问题,有很多答案,但是我发现在接受的答案中使用switch语句有点麻烦,所以这里是我的2分:
我个人最喜欢的方法是使用字典,其中键是源枚举,值是目标枚举,所以在这个问题上,我的代码看起来像这样:
1 2 3 4 5 6 7 8 9 10 | var genderTranslator = new Dictionary<TheirGender, MyGender>(); genderTranslator.Add(TheirGender.Male, MyGender.Male); genderTranslator.Add(TheirGender.Female, MyGender.Female); genderTranslator.Add(TheirGender.Unknown, MyGender.Unknown); // translate their to mine var myValue = genderTranslator[TheirValue]; // translate mine to their var TheirValue = genderTranslator .FirstOrDefault(x => x.Value == myValue).Key;; |
当然,可以将其包装在静态类中,并用作扩展方法:
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 | public static class EnumTranslator { private static Dictionary<TheirGender, MyGender> GenderTranslator = InitializeGenderTranslator(); private static Dictionary<TheirGender, MyGender> InitializeGenderTranslator() { var translator = new Dictionary<TheirGender, MyGender>(); translator.Add(TheirGender.Male, MyGender.Male); translator.Add(TheirGender.Female, MyGender.Female); translator.Add(TheirGender.Unknown, MyGender.Unknown); return translator; } public static MyGender Translate(this TheirGender theirValue) { return GenderTranslator[theirValue]; } public static TheirGender Translate(this MyGender myValue) { return GenderTranslator.FirstOrDefault(x => x.Value == myValue).Key; } } |
可以使用ToString()将第一个枚举转换为其名称,然后使用Enum.Parse()将字符串转换回另一个枚举。如果目标枚举不支持该值(即对于"未知"值),则会引发异常。