2017-10-07 64 views
0

我爲我的問題尋找解決方案,但到目前爲止我無法弄清楚如何去做。如何將一個整數標記爲枚舉的通用列表?

我需要獲取由int值標記的enum的值列表。
我能夠在特定情況下做到這一點,但我想爲泛型枚舉器創建一個通用函數。

爲specicic情況下,代碼是:

 IList<MyEnum> EnumList= new List<MyEnum>(); 
     MyEnum EnumIUseToFlag= (MyEnum)intToParse; 

     foreach (MyEnumitem in Enum.GetValues(typeof(MyEnum))) 
     { 
      if (EnumIUseToFlag.HasFlag(item)) 
      { 
       EnumList.Add(item); 
      } 
     } 

現在,對於一般的方法我試圖像:

public static IList<T> GetFlaggedValues<T>(int intValue) where T : struct, IConvertible 
    { 

     if (!typeof(T).IsEnum) 
     { 
      throw new ArgumentException("T must be an enumerated type"); 
     } 

     IList<T> listToReturn = new List<T>(); 
     Enum enumToParse = Enum.Parse(typeof(T), intValue.ToString()) as Enum; 
     foreach (T item in Enum.GetValues(typeof(T))) 
     { 
      // here I am not able to cast item in the integer 
      //values i need to use in order to flag my enum 

     } 

     return listToReturn; 
    } 

回答

2

答案很簡單is--不使用泛型。這個問題不需要。使用良好的舊繼承並將該標誌作爲System.Enum傳遞,這是所有枚舉的基類。

public static IList<Enum> GetFlaggedValues(Enum flag) 
{ 
    return Enum 
     .GetValues(flag.GetType()) 
     .Cast<Enum>() 
     .Where(e => e.HasFlag(flag)) 
     .ToList(); 
} 

這裏有一個簡單的測試:

enum MyEnum 
{ 
    Red = 0xF00, 
    Orange = 0xFF0, 
    Yellow = 0x0F0, 
    Green = 0x0FF, 
    Blue = 0x00F, 
    Purple = 0xF0F 
} 

public static void Main() 
{ 
    var list = GetFlaggedValues(MyEnum.Blue); 
    foreach (var e in list) 
    { 
     Console.WriteLine(e); 
    } 
} 

輸出:

Blue 
Green 
Purple 

由於我們使用的是Enum基本類型的方式,這是不可能調用此方法與非-enum參數,所以不需要進行混亂的驗證檢查並拋出異常。不能用c#中的泛型來做到這一點。

另一方面,可能真的困擾你,返回類型是List<Enum>而不是List<MyEnum>。精細。如果你堅持一個強類型的列表上的一個結果,你可以只投來回,就像這樣:

public static IList<T> GetFlaggedValues<T>(T input) where T : struct, IConvertible 
{ 
    Enum flag = input as Enum; 
    if (flag == null) return new List<T>(); 
    return Enum 
     .GetValues(typeof(T)) 
     .Cast<Enum>() 
     .Where(e => e.HasFlag(flag)) 
     .Cast<T>() 
     .ToList(); 
} 

注意,在最後一個例子,如果輸入實際上不是一個枚舉,我剛回一個空的列表,這似乎是合理的行爲,因爲它準確地反映了枚舉中的哪些值匹配 - 都不是。但是如果你願意,你可以拋出異常。另外,您可能已經注意到我更改了您的原型,以便您可以傳遞枚舉本身而不是整數。這允許編譯器推斷出類型,所以你可以叫

var list = GetFlaggedValues(MyEnum.Blue); 

而不必鍵入

var list = GetFlaggedValues<MyEnum>((int)MyEnum.Blue); //Ugly 

的。如果你想傳遞一個整數,你可以隨時施放它,就像這樣:

var list = GetFlaggedValues((MyEnum)0xF0F); 

...並且編譯器會推斷出<MyEnum>位。在DotNetFiddle

0

的完整代碼會爲你工作:

public static IList<T> GetFlaggedValues<T>(ulong intValue) where T : struct 
    { 
     if (!typeof(T).IsEnum) 
     { 
      throw new ArgumentException("T must be an enumerated type"); 
     } 
     var flagAttrib = Attribute.GetCustomAttribute(typeof(T), typeof(FlagsAttribute)); 
     if(flagAttrib==null) 
     { 
      throw new ArgumentException("T must have [Flags] attribute."); 
     } 

     List<T> vals = new List<T>(); 
     foreach (var e in Enum.GetValues(typeof(T))) 
     { 
      var item = Convert.ToUInt64(e); 
      if ((item & intValue) != 0) 
       vals.Add((T)Enum.ToObject(typeof(T), item)); 
     } 
     return vals; 
    } 
0

裏面的foreach你可以添加下一行:

 var itemAsEnumValue = (Enum)Enum.Parse(typeof(T), item.ToString()); 

     if (enumToParse.HasFlag(itemAsEnumValue)) 
     { 
      listToReturn.Add(item); 
     } 

Here is working .netfiddle example