2009-11-30 215 views
80

我有例如“Gender”(Male =0 , Female =1)的枚举和我有有它自己的性别枚举服务另一个枚举(Male =0 , Female =1, Unknown =2枚举转换成另一种类型的枚举

我的问题是如何能我写了一些快速又好用的东西来将他们的枚举转换为我的东西?

+4

你想将“未知”转换为? – 2009-11-30 06:27:11

+0

当两者的值相同时,您可以将枚举类型化为其他枚举类型请参阅http://ideone.com/7lgvgf – 2015-11-03 08:57:33

回答

63

使用的扩展方法作品相当整齐,使用内特提出两个转换方法时:

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 
    } 
} 

显然没有必要使用单独的类,如果你不想。我的首选是保持扩展方法按它们适用的类/结构/枚举分组。

20

为了彻底,我通常会创建一对函数,一个采用Enum 1并返回Enum 2,另一个采用Enum 2并返回Enum 1.每个函数都包含一个case语句,将输入映射到输出,默认情况下会抛出一个消息抱怨意外值的例外。

在这种特殊情况下,您可以充分利用男性和女性的整数值相同的事实,但是我会避免这种情况,因为如果任何一种枚举在未来发生变化,它都会变得骇人,并且可能会破坏。

+7

+1我曾见过许多开发人员放弃使用枚举的整数值转换它们的愿望,但是这是非常容易出错的。老式的书写方法写出2个功能已经证明它的价值随着时间的推移... – Hemant 2009-11-30 06:33:24

130

鉴于Enum1 value = ...,然后如果你的名字的意思是:

Enum2 value2 = (Enum2) Enum.Parse(typeof(Enum2), value.ToString()); 

如果通过数值的意思是,你通常可以只投:

Enum2 value2 = (Enum2)value; 

(跟投,你可能想使用Enum.IsDefined来检查有效值,虽然)

+4

这是更好的答案 – Nicholas 2016-05-03 12:42:42

0

您可以使用ToString()将第一个枚举转换为它的名称,然后Enum.Parse()将字符串转换回到另一个枚举。这将抛出一个异常,如果该值不受目标枚举(即一个“未知”值)

6

你可以写像下面这样的简单功能的支持:

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 
    } 
} 
37

只投一个成int,然后将其转换为其他枚举(考虑到你要基于价值的映射完成):

Gender2 gender2 = (Gender2)((int)gender1); 
+2

虽然它不大可能看到它是'在野外',并且极不可能是性别的情况,存在一些由long(或ulong)支持的枚举,而不是具有定义在int.MaxValue之上(或低于int.MinValue)成员的int,在这种情况下,cast到'int'可能会溢出,你最终会得到一个应该定义的未定义的枚举值。当然是 – 2013-07-08 15:04:09

+0

。正确的方法是(Gender2)((插入基础类型here)gender1),但我认为上面的例子给出了正确的想法,所以我不会改变它。 – 2013-07-10 07:53:15

+2

这需要两个枚举以相同的顺序具有相同的值。虽然它解决了这个特定的问题,但这非常脆弱,我不会在一般情况下将它用于枚举映射。 – sonicblis 2013-11-13 19:30:17

12

你可以写一个简单的通用扩展方法,这样

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

我写了一套扩展方法,同时为几种不同的Enum s工作。其中一个特别适用于您正在尝试完成的任务,并处理Enum s,FlagsAttribute以及Enum s具有不同的基础类型。

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的类型,就像你正在尝试做的那样。

public static tEnum ChangeType<tEnum>(this Enum e) where tEnum : IComparable 
{ 
    return SetFlags(e, default(tEnum), true, false); 
} 

被警告,虽然,你可以在任何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>(); 
} 

可变turtle将具有Turtle.Blue的值。

但是,使用此方法存在未定义Enum值的安全性。例如:

static void Main(string[] args) 
{ 
    Turtle turtle = Turtle.Yellow; 
    WriteAccess access = turtle.ChangeType<WriteAccess>(); 
} 

在这种情况下,access将被设置为WriteAccess.ReadWrite,由于WriteAccessEnum具有3.

FlagsAttribute和那些混合Enum•不用它的另一个副作用的最大值转换过程不会导致它们的值之间出现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>(); 
} 

在这种情况下,letters将具有Letters.H代替Letters.D一个值,因为Flavors.Peach背衬值是8。另外,从Flavors.Cherry | Flavors.GrapeLetters转换将产生Letters.C,它可以显得不直观。

3

这里是一个扩展方法的版本,如果有人有兴趣

public static TEnum ConvertEnum<TEnum >(this Enum source) 
    { 
     return (TEnum)Enum.Parse(typeof(TEnum), source.ToString(), true); 
    } 

// Usage 
NewEnumType newEnum = oldEnumVar.ConvertEnum<NewEnumType>(); 
+0

这种情况并不存在,这不意味着这两个枚举具有相同的数值吗? – kuskmen 2017-05-17 07:19:54

+0

不,这是按字符串名称转换的。所以Enum.Foo(1)将转换为Enum2.Foo(2),即使它们的数值不同。 – Justin 2017-05-31 23:40:46

8

如果我们有:

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; 

如果要涵盖在“=”号右边的枚举比左侧的枚举多个值的情况下 - 你会写自己的方法/字典来覆盖别人的建议。

+0

你的回答就像问一个问题!?如果是,这不是一个答案,如果没有[上述类似的答案](http://stackoverflow.com/a/1818786/4519059);)。 – 2016-02-15 10:26:32

0

我知道这是一个老问题,有很多答案,但是我发现,使用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; 
    } 

}