一种解析带有'标志'的.net枚举字符串或int值的方法

本文关键字:字符串 枚举 net int 方法 标志 一种 | 更新日期: 2023-09-27 17:53:40

有一种计算枚举元素的好方法,使用以下方法:

// 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的枚举构建的值除外。例如,对于这个enum和一个值:

[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.");

一种解析带有'标志'的.net枚举字符串或int值的方法

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

看起来在c# 4.0中找到了一个很好的工作。从这里。一旦将整数值解析为枚举,就可以使用它来查看该值是否有效。这将适用于组合标志。

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

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

为什么不直接使用enumt . 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

首先尝试将字符串转换为"底层类型",如果成功-将其强制转换为MyEnum,这就是您需要的。如果转换失败-尝试使用Enum.Parse。如果它也失败-那是一个非常糟糕的输入(抛出异常)


更新:不需要测试int转换enum.Parse(typeof(MyEnum), "9")返回MyEnum.One | MyEnum.Eight(在框架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;

但是非常脏,抛出异常是一个昂贵的操作,所以这里有性能损失…

使用Enum.Parse。然后检查返回值,确保没有设置非有效标志的位。要做到这一点,创建一个包含所有有效值的位掩码,并将它们与值一起或。如果结果与掩码不同,则设置了一些位,这些位不是有效标志。这并不太繁琐(但在应用此逻辑之前,您需要检查Enum是否实际上是Flags Enum -如果它不是Flags Enum,则使用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;

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

尝试获取所有枚举值和将它们与输入值

按位与
经过10分钟的研究,

看起来真的很合理。^ ^

我发现了一个关于类似问题的链接,一个家伙花了很长时间写了这篇文章,也许你也会觉得很有趣。

将c#标志枚举分解为单独的值进行比较