Enum.Parse fails to cast string

2019-04-29 20:17发布

I'm trying to load some AppSettings into an object. The settings look like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="Logging_default_path" value="C:\Temp" />
    <add key="Logging_max_file_size" value="10485760" />
    <add key="Logging_levels" value="Error,Warning,Info"/>
    <add key="Logging_filename" value="RobinsonLog" />
  </appSettings>
</configuration>

The Logging_levels represents several enum values that are allowed by the settings. I'm trying to load these into my object by using the following code:

Level = (LogLevel)Enum.Parse(typeof(LogLevel), settings["Logging_levels"]);

But this is not working and I'm only getting LogLevel.Info returned, not the value of Loglevel.Error | LogLevel.Warning | LogLevel.Info. The enum is defined as followed:

[Flags]
public enum LogLevel
{
    Error = 0x0,
    Warning = 0x1,
    Info = 0x2,
    Debug = 0x3,
    Performance = 0x4
}

Am I wrong by defining the values in hex? or did I miss something else?

4条回答
戒情不戒烟
2楼-- · 2019-04-29 20:24

The problem isn't the parsing! The problem is the conversion to text, instead. Because the flag values aren't distinct bit masks, there is no deterministic mapping to string and back. As mentioned by others, you should choose the values like e.g.:

[Flags]
public enum LogLevel
{
    None = 0
    Error = 1 << 0,
    Warning = 1 << 1,
    Info = 1 << 2,
    // etc
}

See MSDN: Parsing Enumeration Values

See a demo live: https://ideone.com/8AkSQ

using System;

[Flags] enum Colors { None=0, Red = 1, Green = 2, Blue = 4 };

public class Example
{
   public static void Main()
   {
      string[] colorStrings = { "0", "2", "8", "blue", "Blue", "Yellow", "Red, Green" };
      foreach (string colorString in colorStrings)
      {
         try {
            Colors colorValue = (Colors) Enum.Parse(typeof(Colors), colorString);        
            if (Enum.IsDefined(typeof(Colors), colorValue) | colorValue.ToString().Contains(","))  
               Console.WriteLine("Converted '{0}' to {1}.", colorString, colorValue.ToString());
            else
               Console.WriteLine("{0} is not an underlying value of the Colors enumeration.", colorString);
         }
         catch (ArgumentException) {
            Console.WriteLine("'{0}' is not a member of the Colors enumeration.", colorString);
         }
      }
   }
}

Output:

Converted '0' to None.
Converted '2' to Green.
8 is not an underlying value of the Colors enumeration.
'blue' is not a member of the Colors enumeration.
Converted 'Blue' to Blue.
'Yellow' is not a member of the Colors enumeration.
Converted 'Red, Green' to Red, Green.

Performance Note:

If performance is important, do not rely on Enum.Parse :)

See How should I convert a string to an enum in C#?

查看更多
何必那么认真
3楼-- · 2019-04-29 20:34

http://msdn.microsoft.com/en-us/library/essfb559.aspx

The value parameter contains the string representation of an enumeration member's underlying value or named constant, or a list of named constants delimited by commas (,). One or more blank spaces can precede or follow each value, name, or comma in value. If value is a list, the return value is the value of the specified names combined with a bitwise OR operation.

So it should work, and ik looks like it does:

LogLevel level = (LogLevel)Enum.Parse(typeof(LogLevel), "Error,Warning");

if ((level & LogLevel.Error) == LogLevel.Error)
{
    Console.WriteLine("Error");
}

if ((level & LogLevel.Warning) == LogLevel.Warning)
{
    Console.WriteLine("Warning");
}

if ((level & LogLevel.Info) == LogLevel.Info)
{
    Console.WriteLine("Info");
}

Gives me "Error" and "Warning". However, by inspecting the level variable in Visual Studio, it only shows "Warning". Perhaps that set you off. ;-)


Edit: @svick and @jv42 are right, it are your flag values that are wrong.

查看更多
兄弟一词,经得起流年.
4楼-- · 2019-04-29 20:35

Proper flag values might help (each value should set a different bit):

[Flags]
public enum LogLevel
{
    None = 0x0,
    Error = 0x1,
    Warning = 0x2,
    Info = 0x4,
    Debug = 0x8,
    Performance = 0x10
}

Note: you can remove the 'None' if you wish.

查看更多
ら.Afraid
5楼-- · 2019-04-29 20:36

Your enum values are going to cause problems.

The values of a Flags enum must be powers of two, and you shouldn't use 0 for any value other than some kind of empty/none/nothing indicator.

Does this make any difference?

[Flags]
public enum LogLevel
{
    None        =  0
    Error       =  1,
    Warning     =  2,
    Info        =  4,
    Debug       =  8,
    Performance = 16
}
查看更多
登录 后发表回答