将枚举转换为另一种types的枚举
我有一个例如“ Gender
”( Male =0 , Female =1
)的枚举,我有另一个服务,它有自己的性别枚举( Male =0 , Female =1, Unknown =2
)
我的问题是,我怎么能写一些快速的,很好的从他们的枚举转换为我的?
当使用Natebuild议的两种转换方法时,使用扩展方法的工作非常巧妙:
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 } }
显然如果你不想要的话,不需要使用单独的类。 我的首选是保持扩展方法分组,他们适用的类/结构/枚举。
鉴于Enum1 value = ...
,那么如果你的意思是名字:
Enum2 value2 = (Enum2) Enum.Parse(typeof(Enum2), value.ToString());
如果你的意思是数值,你通常可以施放:
Enum2 value2 = (Enum2)value;
(与演员,你可能想要使用Enum.IsDefined
来检查有效的值,虽然)
只需将其中一个转换为int,然后将其转换为另一个枚举(考虑您希望根据值完成映射):
Gender2 gender2 = (Gender2)((int)gender1);
为了彻底,我通常创build一对函数,一个采取枚举1并返回枚举2,另一个采用枚举2并返回枚举1.每个包含一个case语句映射input到输出,默认情况下抛出一个exception消息抱怨意想不到的价值。
在这个特殊的情况下,你可以利用男性和女性的整数值相同的事实,但是我会避免这样做,因为如果任何一个枚举在将来发生变化,那么它会被破解。
你可以写这样一个简单的通用扩展方法
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()); }
如果我们有:
enum Gender { M = 0, F = 1, U = 2 }
和
enum Gender2 { Male = 0, Female = 1, Unknown = 2 }
我们可以安全地做
var gender = Gender.M; var gender2 = (Gender2)(int)gender;
甚至
var enumOfGender2Type = (Gender2)0;
如果您想要覆盖“=”符号右侧的枚举值比左侧的枚举值多的情况,您将不得不编写自己的方法/字典来覆盖其他人所build议的方法/字典。
你可以写一个简单的函数,如下所示:
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 } }
如果有人感兴趣,这里有一个扩展方法版本
public static TEnum ConvertEnum<TEnum >(this Enum source) { return (TEnum)Enum.Parse(typeof(TEnum), source.ToString(), true); } // Usage NewEnumType newEnum = oldEnumVar.ConvertEnum<NewEnumType>();
我写了一组扩展方法,回来几个不同种类的Enum
的工作。 其中一个特别适用于您正在尝试完成的任务,并使用FlagsAttribute
以及具有不同基础types的Enum
来处理Enum
。
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; }
从那里你可以添加其他更具体的扩展方法。
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); }
这个将改变Enum
的types,就像你正在做的那样。
public static tEnum ChangeType<tEnum>(this Enum e) where tEnum : IComparable { return SetFlags(e, default(tEnum), true, false); }
不过要注意的是,你可以使用这种方法在任何Enum
和任何其他Enum
之间进行转换,即使那些没有标志的Enum
也是如此。 例如:
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>(); }
variablesturtle
将有一个Turtle.Blue
值。
但是,使用这种方法从未定义的Enum
值是安全的。 例如:
static void Main(string[] args) { Turtle turtle = Turtle.Yellow; WriteAccess access = turtle.ChangeType<WriteAccess>(); }
在这种情况下, access
将被设置为WriteAccess.ReadWrite
,因为WriteAccess
Enum
的最大值为3。
将FlagsAttribute
和没有它的Enum
s混合的另一个副作用是转换过程不会导致它们的值之间1到1的匹配。
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>(); }
在这种情况下,由于Flavors.Peach
的支持值是8,所以letters
将具有Letters.H
而不是Letters.D
的值。另外,从Flavors.Cherry | Flavors.Grape
Flavors.Cherry | Flavors.Grape
to Letters
会产生Letters.C
,这看起来Letters.C
直观。
您可以使用ToString()将第一个枚举转换为其名称,然后使用Enum.Parse()将该string转换回另一个Enum。 如果目标枚举不支持该值,则会抛出exception(即,对于“未知”值)
我知道这是一个古老的问题,并有很多答案,但是我发现在接受的答案中使用switch语句有点麻烦,所以这里是我的2美分:
我个人最喜欢的方法是使用一个字典,其中关键是源枚举和值是目标枚举 – 所以在问题的情况下,我的代码将如下所示:
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;;
当然,这可以被包装在一个静态类中,并被用作扩展方法:
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; } }