9

在 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); 我们将打印出他的全名!那么为什么会这样呢?

4

3 回答 3

21

枚举类型是不同的,但是你被 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 语句

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。
  • 从任何枚举类型到任何其他枚举类型。

通过将任何参与的枚举类型视为该枚举类型的基础类型,然后在结果类型之间执行隐式或显式数字转换来处理两种类型之间的显式枚举转换。例如,给定一个具有 int 基础类型的枚举类型 E,从 E 到 byte 的转换被处理为从 int 到 byte 的显式数字转换(第 6.2.1 节),从 byte 到 E 的转换被处理为从字节到整数的隐式数字转换(第 6.1.2 节)。

于 2008-12-09T09:21:59.790 回答
2

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

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

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

于 2008-12-09T09:13:59.383 回答
0

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

public enum Cats : byte { ... }
public enum Dogs : int { ... }
于 2008-12-09T16:36:02.393 回答