我读过一些SO帖子,似乎最基本的操作都缺失了。

public enum LoggingLevel
{
    Off = 0,
    Error = 1,
    Warning = 2,
    Info = 3,
    Debug = 4,
    Trace = 5
};

if (s == "LogLevel")
{
    _log.LogLevel = (LoggingLevel)Convert.ToInt32("78");
    _log.LogLevel = (LoggingLevel)Enum.Parse(typeof(LoggingLevel), "78");
    _log.WriteDebug(_log.LogLevel.ToString());
}

这不会导致异常,它很乐意存储78。是否有一种方法来验证进入枚举的值?


当前回答

Use:

Enum.IsDefined ( typeof ( Enum ), EnumValue );

其他回答

Use:

Enum.IsDefined ( typeof ( Enum ), EnumValue );

为了处理[Flags],你也可以使用c# Cookbook中的这个解决方案:

首先,添加一个新的ALL值到你的枚举:

[Flags]
enum Language
{
    CSharp = 1, VBNET = 2, VB6 = 4, 
    All = (CSharp | VBNET | VB6)
}

然后,检查值是否在ALL中:

public bool HandleFlagsEnum(Language language)
{
    if ((language & Language.All) == language)
    {
        return (true);
    }
    else
    {
        return (false);
    }
}

一种方法是依赖于强制转换和枚举到字符串的转换。当将int转换为Enum类型时,int要么被转换为相应的Enum值,要么如果没有为int定义Enum值,则结果Enum仅包含int作为值。

enum NetworkStatus{
  Unknown=0,
  Active,
  Slow
}

int statusCode=2;
NetworkStatus netStatus = (NetworkStatus) statusCode;
bool isDefined = netStatus.ToString() != statusCode.ToString();

没有对任何边缘情况进行测试。

我知道这是一个老问题,但我今天遇到了这个问题,我想扩展Josh Comley的答案(https://stackoverflow.com/a/23177585/3403999)

Josh的回答中有几个错误的假设,我想指出:

It assumes that the '-' is always the negative sign. I don't know if there is any cultures that use a different sign, but .Net certainly allows for it in the NumberFormatInfo (https://learn.microsoft.com/en-us/dotnet/api/system.globalization.numberformatinfo.negativesign?view=net-5.0). About the only one I can think of that might be common is the parenthesis, ie (1) == -1. Enum members have to start with an alphabetic character. Specifically, I know you can use an underscore as the first char. IE, enum MyEnum { _One = 1 } is valid. Not really sure this exactly wrong, but it made the assumption that anything outside the range of '0' to '9' and '-' is a valid alphabetic character. It seemed like a bad assumption cause there are control characters outside that range that would return true - albeit, I don't think you can get those control characters into an enum member name without it throwing a compile error.

总之,这是我的最新解决方案:

public static bool IsValid<TEnum>(this TEnum value) where TEnum : System.Enum
{
    char first = value.ToString()[0];
    return (char.IsLetter(first) || first == '_');
}

我发现可以在枚举成员名中使用来自其他语言的Unicode字母(https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/identifier-names)。在这方面,我的解决办法仍然可行。我使用以下enum进行测试:enum MyEnum {\u05D0}。已编译的枚举,IsValid返回true。

我很好奇,与使用带有枚举值(enumenumvalues (typeof(TEnum))填充的HashSet的静态helper类相比,走这条路会带来什么样的性能打击,其中您可以检查HashSet是否包含enum值。这个想法是两个Enum。GetValues和Enum。IsDefined只是对昂贵的反射命中的包装,所以你用GetValues做一次反射,缓存结果,然后只检查HashSet。

我使用StopWatch和Random运行了一个相当简单的测试,它将生成有效和无效的enum值,然后我通过3个不同的方法运行它们:ToString方法、GetValues HashSet方法和IsDefined方法。每个方法都是int。执行时间。结果:

当我运行20亿次时,ToString平均每次大约2分钟。 GetValues HashSet每次运行20亿次大约50秒。 每次运行20亿次,IsDefined大约5分钟。

因此,如果性能是一个问题,或者您正在进行循环,那么推荐IsDefined的所有解决方案可能都不是一个好主意。如果您只是在单个实例上使用它来验证用户输入,那么这可能无关紧要。

对于HashSet,对于运行它的每个不同枚举,性能都会受到较小的影响(因为第一次运行一个新的枚举类型会生成一个新的静态HashSet)。不科学,但似乎我的PC上的盈亏平衡点是单个枚举运行大约200k到300k次,然后才开始使用ToString方法执行。

ToString方法虽然不是最快的,但它在处理IsDefined和HashSet都不能容纳的Flags枚举方面有额外的好处。

如果性能确实是一个问题,不要使用这3种方法中的任何一种。相反,编写一个方法来验证针对该枚举优化的特定枚举。

还要注意,我的测试使用的是相对较小的枚举(大约5个元素)。我不知道当你开始使用更大的枚举时,ToString和HashSet之间的性能如何。

使用Enum.IsDefined。