我读过一些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。是否有一种方法来验证进入枚举的值?


当前回答

一种方法是依赖于强制转换和枚举到字符串的转换。当将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();

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

其他回答

Use:

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

一种方法是依赖于强制转换和枚举到字符串的转换。当将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();

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

正如其他人所说,Enum。IsDefined返回false,即使你有一个用FlagsAttribute装饰的enum的有效的位标志组合。

遗憾的是,创建一个为有效位标志返回true的方法有点长:

public static bool ValidateEnumValue<T>(T value) where T : Enum
{
    // Check if a simple value is defined in the enum.
    Type enumType = typeof(T);
    bool valid = Enum.IsDefined(enumType, value);
    // For enums decorated with the FlagsAttribute, allow sets of flags.
    if (!valid && enumType.GetCustomAttributes(typeof(FlagsAttribute), false)?.Any() == true)
    {
        long mask = 0;
        foreach (object definedValue in Enum.GetValues(enumType))
            mask |= Convert.ToInt64(definedValue);
        long longValue = Convert.ToInt64(value);
        valid = (mask & longValue) == longValue;
    }
    return valid;
}

你可能想把GetCustomAttribute的结果缓存到一个字典中:

private static readonly Dictionary<Type, bool> _flagEnums = new Dictionary<Type, bool>();
public static bool ValidateEnumValue<T>(T value) where T : Enum
{
    // Check if a simple value is defined in the enum.
    Type enumType = typeof(T);
    bool valid = Enum.IsDefined(enumType, value);
    if (!valid)
    {
        // For enums decorated with the FlagsAttribute, allow sets of flags.
        if (!_flagEnums.TryGetValue(enumType, out bool isFlag))
        {
            isFlag = enumType.GetCustomAttributes(typeof(FlagsAttribute), false)?.Any() == true;
            _flagEnums.Add(enumType, isFlag);
        }
        if (isFlag)
        {
            long mask = 0;
            foreach (object definedValue in Enum.GetValues(enumType))
                mask |= Convert.ToInt64(definedValue);
            long longValue = Convert.ToInt64(value);
            valid = (mask & longValue) == longValue;
        }
    }
    return valid;
}

注意,上面的代码在T上使用了新的Enum约束,这是c# 7.3以来才有的。您需要在旧版本中传递一个对象值,并对其调用GetType()。

使用Enum.IsDefined。

为了处理[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);
    }
}