2012-07-31 69 views
8

有沒有人有解析枚舉更優雅的解決方案?以下對我來說似乎是一團糟。優雅地解析C#枚舉

UserType userType = (UserType)Enum.Parse(typeof(UserType), iUserType.ToString()); 

回答

13

我經常做一個通用的幫手吧:

public static T ParseEnum<T>(string value) where T:struct 
{ 
    return (T)Enum.Parse(typeof(T), value); 
} 

可以結合起來,與Jon Skeet'sUnstrained Melody(或任何其他職位IL處理器),以獲得在枚舉適當類型的約束,但是可選的。

然後你可以使用它像這樣:

var enumValue = ParseEnum<UserType>(iUserType.ToString()); 

.NET框架4.0還帶有Enum.TryParse這也提供了類似的語法,並提供一種方法來處理,如果解析失敗。例如:

UserType userType; 
if (Enum.TryParse<UserType>(iUserType.ToString(), out userType)) 
{ 
    //Yay! Parse succeeded. The userType variable has the value. 
} 
else 
{ 
    //Oh noes! The parse failed! 
} 
+0

我注意到對於Enum.TryParse(),解析永遠不會失敗,即使我希望它的值不在枚舉中。 我的例子是:https://pastebin.com/fZfT69Lk – Colin 2017-10-07 00:47:04

+0

@Colin - 有趣。這是因爲整數值總是可以轉換爲枚舉值,例如'(TestEnum)4737373'也可以工作和編譯。如果你想強制你的值是一個命名值,你可以使用GetNames來確保它在那裏。 – vcsjones 2017-10-07 12:24:10

3

您可以創建這樣

public static class EnumExtensions 
{ 
    public static T ToEnum<T>(this string s) 
    { 
     return (T)Enum.Parse(typeof(T), s); 
    } 
} 

的extesion方法,然後在代碼中,你可以使用這種方式(MyEnum包含值A和B):

string s = "B"; 
MyEnum e = s.ToEnum<MyEnum>(); 
1

以下是基於@vcsjones版本和反饋的擴展方法,以及來自@Mones示例:

public enum TestEnum 
{ 
    None, 
    A, 
    B, 
}; 

void Main() 
{ 
    var testValues = new List<object>(); 
    testValues.AddRange(Enumerable.Range(-2, 6).Select(i => (object)i)); 
    testValues.AddRange(new List<string>() { String.Empty, "A", "B", "C", null }); 

    foreach (var testValue in testValues) 
    { 
     Console.WriteLine($"Testing value {testValue ?? String.Empty}:"); 
     TestEnum output; 
     var enumValues = Enum.GetNames(typeof(TestEnum)).ToList(); 
     try 
     { 
      if (TestEnum.TryParse(testValue.ToString(), out output)) 
      { 
       Console.WriteLine($"Succeeded with TryParse on {testValue} to {output}"); 
      } 
      else 
      { 
       Console.WriteLine($"Failed to TryParse on {testValue}"); 
      } 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine($"Test harness caught an exception: {ex.ToString()}"); 
     } 

     var toEnumOutput = (testValue ?? String.Empty).ToString().Parse<TestEnum>(); 
     Console.WriteLine($"Parse<TEnum> returned {toEnumOutput}"); 

     Console.WriteLine(); 
     Console.WriteLine(); 
    } 

} 


public static class EnumExtensions 
{ 
    public static TEnum Parse<TEnum>(this string value) where TEnum : struct 
    { 
     TEnum output = default(TEnum); 
     var enumValues = Enum.GetNames(typeof(TEnum)).ToList(); 

     if (Enum.TryParse<TEnum>(value, true, out output)) 
      if (Enum.IsDefined(typeof(TEnum), value) || value.ToString().Contains(",") || enumValues.Contains(output.ToString())) 
      { 
       Console.WriteLine($"Converted '{value}' to {output}."); 
       return output; 
      } 
      else 
      { 
       Console.WriteLine($"{value} is not an underlying value of the enumeration."); 
      } 
     else 
     { 
      Console.WriteLine($"{value} is not a member of the enumeration."); 
     } 
     return default(TEnum); 
    } 
} 

測試工具給出了這樣的輸出:

Testing value -2: 
Succeeded with TryParse on -2 to -2 
-2 is not an underlying value of the enumeration. 
Parse<TEnum> returned None 


Testing value -1: 
Succeeded with TryParse on -1 to -1 
-1 is not an underlying value of the enumeration. 
Parse<TEnum> returned None 


Testing value 0: 
Succeeded with TryParse on 0 to None 
Converted '0' to None. 
Parse<TEnum> returned None 


Testing value 1: 
Succeeded with TryParse on 1 to A 
Converted '1' to A. 
Parse<TEnum> returned A 


Testing value 2: 
Succeeded with TryParse on 2 to B 
Converted '2' to B. 
Parse<TEnum> returned B 


Testing value 3: 
Succeeded with TryParse on 3 to 3 
3 is not an underlying value of the enumeration. 
Parse<TEnum> returned None 


Testing value : 
Failed to TryParse on 
is not a member of the enumeration. 
Parse<TEnum> returned None 


Testing value A: 
Succeeded with TryParse on A to A 
Converted 'A' to A. 
Parse<TEnum> returned A 


Testing value B: 
Succeeded with TryParse on B to B 
Converted 'B' to B. 
Parse<TEnum> returned B 


Testing value C: 
Failed to TryParse on C 
C is not a member of the enumeration. 
Parse<TEnum> returned None 


Testing value : 
Test harness caught an exception: System.NullReferenceException: Object reference not set to an instance of an object. 
    at UserQuery.Main() in C:\Users\Colin\AppData\Local\Temp\3\LINQPad5\_zhvrhwll\query_ludjga.cs:line 49 
is not a member of the enumeration. 
Parse<TEnum> returned None 

參考文獻:

+1

我看到你在努力創造一個研究得很好的答案和一套很好的測試。這真的很棒,但讓我鼓勵你嘗試使用一些單元測試框架。任何一個,他們這些年都很相似。我很想用** xUnit **(我真的很喜歡那個,只是鏈接一個nuget而不用去)來重寫你的測試,告訴你它有多酷/可讀,但是..可能你會受益更多自己做。如果你想嘗試一些東西,請給我留言。 – quetzalcoatl 2017-10-10 18:40:52

+0

嗨@quetzalcoatl - 欣賞反饋。我添加nUnit測試,然後發佈一個鏈接到我的測試類。 – Colin 2017-10-10 20:33:39