【问题标题】:Are enums only named integers, types or neither of both?枚举是否仅命名为整数、类型或两者都不是?
【发布时间】:2008-12-09 09:03:41
【问题描述】:

在 C# 中使用枚举很有趣。取一个为存储您之前定义的 Enum 而创建的通用列表,并在其中添加一些项目。使用 foreach 或 GetEnumerator<T>() 进行迭代,但指定其他一些枚举然后是原始枚举,看看会发生什么。我期待 InvalidCastException 或类似的东西,但它非常有效:)。

为了演示,让我们使用一个简单的控制台应用程序并在那里创建两个枚举:汽车和动物:

    public enum Cars
    {
        Honda = 0,
        Toyota = 1,
        Chevrolet = 2
    }
    public enum Animals
    {
        Dog = 0,
        Cat = 1,
        Tiger = 2
    }

并在 main 方法中执行此操作:

    public static void Main()
    {
        List<Cars> cars = new List<Cars>();
        List<Animals> animals = new List<Animals>();
        cars.Add(Cars.Chevrolet);
        cars.Add(Cars.Honda);
        cars.Add(Cars.Toyota);

        foreach (Animals isItACar in cars)
        {
            Console.WriteLine(isItACar.ToString());
        }
        Console.ReadLine();
    }

它将在控制台中打印:

Tiger
Dog
Cat

为什么会这样?我的第一个猜测是,枚举本身并不是一个类型,它只是和 int,但事实并非如此:如果我们这样写:

Console.WriteLine(Animals.Tiger.GetType().FullName); 我们将打印出他的全名!那为什么会这样呢?

【问题讨论】:

    标签: c# enums


    【解决方案1】:

    枚举类型是不同的,但你被 foreach 中的隐式转换弄糊涂了。

    让我们稍微重写一下你的循环:

    public static void Main()
    {
        List<Cars> cars = new List<Cars>();
        List<Animals> animals = new List<Animals>();
        cars.Add(Cars.Chevrolet);
        cars.Add(Cars.Honda);
        cars.Add(Cars.Toyota);
    
        foreach (Cars value in cars)
        {
            // This time the cast is explicit.
            Animals isItACar = (Animals) value;
            Console.WriteLine(isItACar.ToString());
        }
        Console.ReadLine();
    }
    

    现在的结果让你吃惊吗?希望不会,除非您可以从一个枚举转换到另一个枚举。这只是您的原始代码所做的更明确的版本。

    我认为,在每个 foreach 循环中都隐含了一个强制转换(即使它通常是无操作的)这一事实是大多数开发人员会感到困惑的一点。

    来自 C# 3.0 规范的第 8.8.4 节:

    以上步骤,如果成功, 明确地产生一个集合 C 型、E 型枚举器和元素 类型 T。 表格

    foreach (V v in x)  embedded-statement 
    

    然后扩展为:

    {
        E e = ((C)(x)).GetEnumerator();
        try {
            V v;
            while (e.MoveNext()) {
                v = (V)(T)e.Current;
                embedded-statement
            }
        }
        finally {
            ... // Dispose e
        }
    }
    

    枚举转换本身在第 6.2.2 节中介绍:

    显式枚举转换 是:

    • 从 sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double 或 decimal 到任何枚举类型。
    • 从任何枚举类型到 sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double 或 decimal。
    • 从任何枚举类型到任何其他枚举类型。

    显式枚举转换 两种类型之间的处理由 处理任何参与的枚举类型 作为那个的基础类型 枚举类型,然后执行 隐式或显式数字 结果之间的转换 类型。例如,给定一个枚举类型 E 具有 int 的基础类型,a 处理从 E 到字节的转换 作为显式数字转换 (第 6.2.1 节)从 int 到 byte,以及 处理从字节到 E 的转换 作为隐式数字转换 (§6.1.2)从字节到整数。

    【讨论】:

    • 是的,很好的答案。我现在意识到任何类型的枚举之间的显式转换都不会失败,因为它们实际上是一个整数,并且问题的根源。
    【解决方案2】:

    从概念上讲,枚举是具有字符串表示和数字的静态类型值。当您在枚举上调用 ToString() 时,它将返回字符串表示形式。当您在枚举上调用 GetType() 时,您将获得静态枚举类型。如果您将枚举转换为int,您将获得该枚举的整数值。

    枚举应该是强类型的,但有一些事情你需要注意,例如任何整数都可以转换为任何枚举,即使它没有相应的声明(在这种情况下字符串表示将与数字相同)。

    在 CLR 中,枚举(如 bools)仅被视为 ints,但如果您调用 GetType() 或 GetString(),它会调用执行上述操作的版本。

    【讨论】:

      【解决方案3】:

      您还可以从特定类型派生枚举。

      public enum Cats : byte { ... }
      public enum Dogs : int { ... }
      

      【讨论】:

        猜你喜欢
        • 2016-03-27
        • 2014-07-24
        • 2011-07-08
        • 1970-01-01
        • 1970-01-01
        • 2011-03-14
        • 1970-01-01
        • 2013-11-03
        相关资源
        最近更新 更多