将枚举转换为另一种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; } }