c# - 与解析枚举混淆

标签 c# parsing enums

我正在将字符串类型的数值转换为相应的枚举。在测试我的代码时,我发现了一些让我感到困惑的有趣行为。

使用下面的代码示例,如果/当“s”变量的值与枚举值之一不匹配时,有人可以阐明为什么不抛出异常吗?另外,如何将 sEnum var 设置为 Stooge 枚举定义中不存在的值?

class Program
{
    enum Stooge
    {
        Unspecified,
        Moe,
        Larry,
        Curly,
        Shemp
    }

    static void Main(string[] args)
    {
        while (true)
        {
            Console.WriteLine("Enter a number...");

            string s = Console.ReadLine();
            Stooge sEnum = (Stooge)(int.Parse(s)); //Why doesn't this line throw if s != 0, 1, 2, 3, or 4?

            Console.WriteLine("\r\nYou entered: {0}\r\nEnum String Value: {1}\r\nEnum Int Value: {2}\r\n", s, sEnum.ToString(), (int)sEnum);
        }
    }
}

最佳答案

这是创建 .NET 的人的决定。枚举由另一种值类型(intshortbyte 等)支持,因此它实际上可以具有任何有效值对于那些值类型。

我个人不喜欢这种工作方式,所以我制作了一系列实用方法:

/// <summary>
/// Utility methods for enum values. This static type will fail to initialize 
/// (throwing a <see cref="TypeInitializationException"/>) if
/// you try to provide a value that is not an enum.
/// </summary>
/// <typeparam name="T">An enum type. </typeparam>
public static class EnumUtil<T>
    where T : struct, IConvertible // Try to get as much of a static check as we can.
{
    // The .NET framework doesn't provide a compile-checked
    // way to ensure that a type is an enum, so we have to check when the type
    // is statically invoked.
    static EnumUtil()
    {
        // Throw Exception on static initialization if the given type isn't an enum.
        Require.That(typeof (T).IsEnum, () => typeof(T).FullName + " is not an enum type.");
    }

    /// <summary>
    /// In the .NET Framework, objects can be cast to enum values which are not
    /// defined for their type. This method provides a simple fail-fast check
    /// that the enum value is defined, and creates a cast at the same time.
    /// Cast the given value as the given enum type.
    /// Throw an exception if the value is not defined for the given enum type.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="enumValue"></param>
    /// <exception cref="InvalidCastException">
    /// If the given value is not a defined value of the enum type.
    /// </exception>
    /// <returns></returns>
    public static T DefinedCast(object enumValue)

    {
        if (!System.Enum.IsDefined(typeof(T), enumValue))
            throw new InvalidCastException(enumValue + " is not a defined value for enum type " +
                                           typeof (T).FullName);
        return (T) enumValue;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="enumValue"></param>
    /// <returns></returns>
    public static T Parse(string enumValue)
    {
        var parsedValue = (T)System.Enum.Parse(typeof (T), enumValue);
        //Require that the parsed value is defined
        Require.That(parsedValue.IsDefined(), 
            () => new ArgumentException(string.Format("{0} is not a defined value for enum type {1}", 
                enumValue, typeof(T).FullName)));
        return parsedValue;
    }

    public static bool IsDefined(T enumValue)
    {
        return System.Enum.IsDefined(typeof (T), enumValue);
    }

}

public static class EnumExtensions
{
    public static bool IsDefined<T>(this T enumValue)
        where T : struct, IConvertible
    {
        return EnumUtil<T>.IsDefined(enumValue);
    }
}

这样,我可以说:

if(!sEnum.IsDefined()) throw new Exception(...);

...或者:

EnumUtil<Stooge>.Parse(s); // throws an exception if s is not a defined value.

更新

正如 Brandon Kramer 在评论中指出的那样,C# 7.3 引入了一些新的泛型类型,允许将上面的 where T : struct, IConvertible 替换为 where T : Enum,以便更好地编译时检查传入类型的枚举性。这样您就可以摆脱 EnumUtil 的静态构造函数中的 guard 语句。

关于c# - 与解析枚举混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4892548/

相关文章:

c# - 类型转换器中的枚举值

c++ - 使作用域枚举与基础类型相当

c# - 用于移动设备的 Web - ASP.NET 的最佳实践

时间:2019-05-17 标签:c#devexpresspichart系列点颜色变化

c# - Android Java 到 Mono C# - MapView.LayoutParams

xml - 从 XML 文件中提取标签信息到 Excel 文件

c# - 将数据表加载到数据集中的现有表

java - CET 日期 : Unparseable date

使用sax解析器的java程序

c# - 根据 FXCop 的 CA1008 规则,枚举应具有默认值零。这适用于 C# 吗?