2009-11-30 117 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; 
    } 

}