2008-12-09 99 views
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); 我们将得到他的完全合格的名称打印!那么为什么呢?

回答

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,字节,短,USHORT,INT,UINT,长,ULONG,炭,浮点,双,或十进制到任何enum-type。
  • 从任何枚举类型到字节,byte,short,ushort,int,uint,long,ulong,char,float,double或decimal。
  • 从任何枚举类型到任何其他枚举类型。

显式枚举转换类型 两者之间是由 治疗任何参与枚举类型 作为底层类型 枚举类型的,然后执行之间的 隐式或显式数值 转换处理由此产生的 类型。例如,给定枚举类型 E以及基本类型的int,从E到字节的 转换被处理为 作为从int到字节的显式数字转换 (第6.2.1),并且从字节转换 到E被处理 作为从字节到int的隐式数字转换 (第6.1.2节)。

+1

是非常好的答案。我现在认识到,任何类型的枚举之间的明确映射都不会失败,因为它们实际上是一个整数,并且存在问题的根源。 – Aleksandar 2008-12-10 07:19:57

2

概念上,Enum是一个静态类型的值,包含一个字符串表示和一个数字。当您在枚举上调用ToString()时,它将返回字符串表示形式。当您在枚举上调用GetType()时,您将获得静态枚举类型。如果您将枚举强制转换为int,您将获得枚举的整数值。

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

在CLR中,枚举(如bool s)仅被视为int s,但如果调用GetType()或GetString(),则会调用执行上述操作的版本。

0

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

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