解析使用'Flags'归因的.NET枚举字符串或int值的方法

时间:2011-04-26 19:42:30

标签: c# .net parsing enumeration

使用以下方法可以很好地计算枚举元素:

// memberType is enum type
if (Enum.IsDefined(memberType, valueString))
{
    return Enum.Parse(memberType, valueString);
}
else
{
    try 
    {
        var underlyingValue = Convert.ChangeType(valueString, Enum.GetUnderlyingType(memberType));
        if (Enum.IsDefined(memberType, underlyingValue))
        {
            return underlyingValue;
        }
    }
    catch...
}

这就像魅力一样。除了使用FlagsAttribute标记的枚举构建的值之外。例如,对于此枚举和值:

[Flags]
enum MyEnum {
    One = 0x1,
    Two = One << 1,
    Four = One << 2,
    Eight = One << 3
}

var e = MyEnum.One | MyEnum.Eight;

上述方法不起作用。看起来让它工作的唯一方法是尝试获取所有枚举值,并使用输入值按位和它们。但这有点单调乏味。所以你知道更好的方法吗?

答案:

最终方法如下:

var parsed = Enum.Parse(memberType, valueString);
decimal d;
if (!decimal.TryParse(parsed.ToString(), out d))
{
    return parsed;
}
throw new ArgumentOutOfRangeException(memberInfo.Name, valueString, "Bad configuration parameter value.");

5 个答案:

答案 0 :(得分:4)

  

我想问一个更好的问题,如何检测不良值。

看起来在Nutshell中的C#4.0中找到了一个很好的工作。来自here。将整数值解析为枚举后,可以使用此值并查看该值是否有效。这适用于组合标志。

static bool IsFlagDefined(Enum e)
{
    decimal d;
    return !decimal.TryParse(e.ToString(), out d);
}

答案 1 :(得分:3)

这是预期的行为,因为您可以获得与标志不对应的值。例如,假设值a = 1,b = 2,c = 4,d = 8等(仅标准二进制进展)。值(a&amp; c)或7(a,b&amp; c)可以为5。

答案 2 :(得分:1)

为什么不直接使用Enum.Parse()

var test = MyEnum.One | MyEnum.Eight;
var str = test.ToString();
var back = (MyEnum) enum.Parse(typeof(MyEnum), str); // this returns MyEnum.One | MyEnum.Eight

首先尝试将您的字符串转换为“undelying type”,如果成功 - 将其转换为MyEnum,这就是您所需要的。 如果转换失败 - 请尝试使用Enum.Parse。 如果它也失败了 - 这是一个非常糟糕的输入(抛出异常)


<强>更新 不需要对int转换进行测试enum.Parse(typeof(MyEnum), "9")返回MyEnum.One | MyEnum.Eight(在Framework 2.0到4.0中测试)


更新2: 所以问题确实是“如何找出不好的价值观?”。肮脏的解决方案:

var res = Enum.Parse(targetType, str);
bool isBad;
try
{
    Convert(res.ToString(), underType);
    isBad = true;
}
catch
{
    // convert failed
    isBad = false;
}

if (isBad)
    throw new Exeption();
return res;

但它非常脏并且抛出异常是昂贵的操作,所以这里有性能损失......但它有效)

答案 3 :(得分:1)

使用Enum.Parse。然后检查返回的值,没有设置任何不是有效标志的位。为此,请创建一个包含所有有效值的位掩码,并将它们与值一起使用。如果结果与掩码不同,则设置一些位,这些位不是有效标志。这不是太繁琐(但是在应用此逻辑之前,您需要检查枚举是否实际上是Flags枚举 - 如果它不是Flags枚举,请使用IsDefined。

代码可能会像这样;并且如果您认为每次计算可能过于昂贵(可能不是,但将取决于您的情况),您可以存储预先计算的每种类型的掩码:

object value = Enum.Parse(memberType, valueString);
int numericValue = (int)value;
int definedMask = Enum.GetValues(memberType).Cast<int>().Aggregate(0, (v,a) => v | a);
if ((definedMask | numericValue) != definedMask)
    throw new InvalidOperationException(String.Format("{0} is not a valid {1} value.", valueString, memberType.Name));
return value;

答案 4 :(得分:0)

这是一个很好的问题,你的建议

  

尝试获取所有枚举值和   按位AND与输入值

经过10分钟的研究看起来真的很合理.. ^^

我找到了关于类似问题的一个很好的链接,一个人花了很多时间来写这篇文章,也许你会发现它也很有趣。

Breaking down C# Flags enums into individual values for comparison