2012-09-16 73 views
5

給定一個枚舉這樣的:如何使用泛型創建從枚舉中創建IEnumerable的方法?

public enum City { 
    London = 1, 
    Liverpool = 20, 
    Leeds  = 25 
} 

public enum House { 
    OneFloor = 1, 
    TwoFloors = 2 
} 

我使用下面的代碼給我一個IEnumerable:

City[] values = (City[])Enum.GetValues(typeof(City)); 
var valuesWithNames = from value in values      
    select new { value = (int)value, name = value.ToString() }; 

代碼工作很好,但是我必須爲相當多的做到這一點枚舉。有沒有一種方法可以創建一個通用的方式來做到這一點?

+1

問題是,C#不允許枚舉約束泛型類型。您可以使用Jon Skeet的[不受約束的旋律](http://code.google.com/p/unconstrained-melody/)。 – Adam

+0

如果您僅在運行時需要'IEnumerable',則可以使用反射。否則,您可能會考慮使用[模板](http://msdn.microsoft.com/zh-cn/library/bb126445.aspx)和反射。 – Guillaume

回答

1

此功能可以幫助你:

public static IEnumerable<KeyValuePair<int, string>> GetValues<T>() where T : struct 
{ 
     var t = typeof(T); 
     if(!t.IsEnum) 
      throw new ArgumentException("Not an enum type"); 

     return Enum.GetValues(t).Cast<T>().Select (x => 
       new KeyValuePair<int, string>(
        (int)Enum.ToObject(t, x), 
        x.ToString())); 
} 

用法:

var values = GetValues<City>(); 
+0

'InvalidOperationException'被定義爲*「當方法調用對於對象的當前狀態無效時引發的異常。「*這似乎是一個非常容易引起誤解的異常拋出 – Adam

+0

@codesparkle也許,我已經將它改爲'ArgumentException' – Magnus

+0

類似於* UnconstrainedMelody *中定義的TypeArgumentException將是理想的。 'ArgumentException'雖然*(「當提供給方法的參數之一無效時引發的異常。」)* – Adam

1

爲什麼不:

IEnumerable<object> GetValues<T>() 
    { 
     return Enum.GetValues(typeof (T)) 
        .Cast<T>() 
        .Select(value => new {  
              value = Convert.ToInt32(value), 
              name = value.ToString() 
             }); 

    } 

所以,你可以使用:

var result = GetValues<City>(); 

如果你想使約束通用Tenum,因爲enum不能用作通用contraint直接,但enum繼承自接口IConvertible,相信這種方式沒問題:

IEnumerable<object> GetValues<T>() where T: struct, IConvertible 
{} 

通過Dictionary要更換IEnumerable<object>

Dictionary<int, string> GetValues<T>() where T : struct, IConvertible 
{ 
    return Enum.GetValues(typeof (T)).Cast<T>() 
       .ToDictionary(value => Convert.ToInt32(value), 
          value => value.ToString()); 
} 

編輯:由於馬格努斯的評論,如果您需要確保項目的順序,字典是不是選項。定義你自己的強類型會更好。

+0

我看到了返回字典的兩個問題:首先它是無序的。其次,如果字典不用於查找,似乎沒有必要返回字典。 – Magnus

+0

@Magnus:真正的無序,我使用的原因是Dictionary是比IEmmerable 更強的類型。 –

3

使用喬恩斯基特的unconstrained melody

using UnconstrainedMelody; 

你可以把你的枚舉值成Dictionary<int, string>,然後列舉了他們:

var valuesAsDictionary = Enums.GetValues<City>() 
           .ToDictionary(key => (int)key, value => value.ToString()); 

但你可能甚至都不需要做。爲什麼不直接枚舉數值直接:

foreach (var value in Enums.GetValues<City>()) 
{ 
    Console.WriteLine("{0}: {1}", (int)value, value); 
} 
+0

爲什麼要轉換爲int而不是'T'?枚舉不必是int ,並且沒有理由不能返回「Dictionary '而不是 – Lee

+1

@Lee在這個問題中,她明確地想要int和string – Magnus

+0

@Lee但是當你需要的所有信息都存在時,爲什麼要創建一個字典?在枚舉值本身內?這是我在答案的後半部分試圖表達的觀點。 – Adam