zoukankan      html  css  js  c++  java
  • C# 枚举基础篇(转载)

    Q:在C#里,我们如何表达枚举类型?

    A:你可以使用enum关键字(keyword)来声明一个枚举类型(enum type):

    //Code #1
    public enum Alignment  
    {      
       Left,    
       Center,     
       Right 
    }

    Q:C#枚举类型是值类型(value type)还是引用类型(reference type)?

    A:枚举类型都是值类型。

    Q:System.Enum是枚举类型么?

    A:不是。

    Q:System.Enum与枚举类型(enum type)有什么关系?

    A:System.Enum是一个抽象类(abstract class),所有枚举类型都直接继承自它,当然也同时继承了它的所有成员。

    Q:那么System.Enum属于引用类型啦?

    A:是的。

    Q:既然System.Enum是引用类型,而枚举类型又是直接继承自System.Enum的,那为什么枚举类型却不是引用类型?

    A:这种继承关系是隐式的并由编译器负责展开,上面Code #1的Alignment枚举被展开后的IL代码如下:

    Code #02
    // Code #02  
    .class public auto ansi sealed Aligment         
         extends [mscorlib]System.Enum  
    {      
         .field 
    public static literal Aligment Left = int32(0x00000000)     
         .field 
    public static literal Aligment Center = int32(0x00000001)     
         .field 
    public static literal Aligment Right = int32(0x00000002)     
         .field 
    public specialname rtspecialname int32 value__  
    }  

    从声明中,你可以看到Aligment的确是继承自System.Enum的,只是你不能在C#里显式声明这种继承关系。

    Q:但你好像没有回答为什么枚举类型继承自一个引用类型后,却还是值类型!

    A:你知道,所有的值类型都是System.ValueType的后代,枚举类型也不例外,枚举类型直接继承自System.Enum,而System.Enum却又直接继承自System.ValueType的,所以,枚举类型也是System.ValueType的后代。

    Q:慢着!从System.ValueType派生出来的类型不都应该是值类型吗?为什么System.Enum会是引用类型?

    A:正确的说法应该是“值类型都是System.ValueType的后代”,但System.ValueType的后代不全是值类型,System.Enum就是唯一的特例!在System.ValueType的所有后代中,除了System.Enum之外其它都是值类型。事实上,我们可以在.NET的源代码中找到System.Enum的声明:

    //Code #03
    public abstract class Enum : ValueType, IComparable, IFormattable, IConvertible  

    请注意,.NET Framework SDK v2.0.3600.0 Documentation中的Enum声明是错的:

    public abstract struct Enum : IComparable, IFormattable, IConvertible

    Q:开始头晕了,究竟C#枚举类型、System.Enum、System.ValueType、值类型和引用类型之间存在着什么样的关系?

    A:简单的说,

    1. 所有枚举类型(enum type)都是值类型。
    2. System.Enum和System.ValueType本身是引用类型。
    3. 枚举类型(enum type)都是隐式的直接继承自System.Enum,并且这种继承关系只能由编译器自动展开。但System.Enum本身不是枚举类型(enum type)。
    4. System.Enum是一个特例,它直接继承自System.ValueType(参见Code #03),但本身却是一个引用类型。

    好吧,现在来看看下面代码,你能猜得出它的输出结果吗?

    Code #04
    // Code #04  
    static void Main() 
     {      
          Type t 
    = typeof(System.Enum);     
           
    if (t.IsEnum)         
               Console.WriteLine(
    "I'm enum type.");    
           
    if (t.IsValueType)        
               Console.WriteLine(
    "I'm value type.");
     }  

    请别惊讶于程序的运行结果没有任何输出!对于第一个判断,我们很清楚System.Enum并不是枚举类型。但第二个判断呢?System.Enum明明继承自System.ValueType,却不承认是System.ValueType的后代!这是.NET上的一个特例,恰恰体现出System.Enum是特殊性。

    Q:既然枚举类型是值类型,自然会涉及到装箱和拆箱(boxing and unboxing)的问题,那么枚举类型会被装箱成什么呢?[Updated]

    A:枚举类型可以被装箱成System.Enum、System.ValueType、System.Object或者System.IConvertible、System.IFormattable、System.IComparable。

    注意:在.NET 1.1上,枚举类型只能被装箱到System.Enum、System.ValueType、System.Object;而在.NET 2.0上,枚举类型还能被装箱到System.Enum所实现的三个接口:System.IConvertible、System.IComparable、System.IFormattable。对应的装箱操作既可以为隐式的也可以是显式的。

    Code #05
    // Code #05  
    // See Code #01 for Alignment.  
    static void Main()  
    {      
          Alignment a 
    = Alignment.Center;      
          Console.WriteLine(a.ToString());     
          Console.WriteLine(a);  
    }  

    对应的IL代码是:

    Code #06 
    // Code #06  
    .method private hidebysig static void Main() cil managed 
     {     
        .entrypoint      
        
    // Code Size: 32 byte(s)      
       .maxstack 1      
       .locals (         
           EnumerationFaq.Alignment alignment1)    
        L_0000: ldc.i4.
    1      
        L_0001: stloc.
    0      
        L_0002: ldloc.
    0      
        L_0003: box EnumerationFaq.Alignment  
        L_0008: call instance 
    string [mscorlib]System.Enum::ToString()    
        L_000d: call 
    void [mscorlib]System.Console::WriteLine(string)    
        L_0012: nop      
        L_0013: ldloc.
    0     
        L_0014: box EnumerationFaq.Alignment     
        L_0019: call 
    void [mscorlib]System.Console::WriteLine(object)   
        L_001e: nop    
       L_001f: ret  
    }  

    从IL代码中我们可以看到枚举类型被装箱两次。第一次(L_0003)被装箱成System.Enum,而第二次(L_0014)就被装箱成System.Object。

    但如果你让编译器自动为你选择装箱类型的话,它会优先考虑System.Enum:

    Code #07
    // Code #07  
    // See Code #01 for Alignment.  
    class Program 
    {    
        
    static void Main()  
        {        
             Alignment a 
    = Alignment.Center;     
             Print(a);    
        }      
        
    static void Print(IConvertible c)   
        {         
           Console.WriteLine(c);   
        }      
        
    static void Print(IFormattable f)    
        {        
           Console.WriteLine(f);  
        }       
        
    static void Print(IComparable c)   
        {          
            Console.WriteLine(c);  
        }      
        
    static void Print(Object o)    
        {        
            Console.WriteLine(o);   
        }     
        
    static void Print(ValueType v)   
        {          
           Console.WriteLine(v);    
        }    
        
    static void Print(Enum e)   
        {         
           Console.WriteLine(e);    
        }  
    }  

    上面的代码将被编译成如下的IL:

    Code #08
    // Code #08  
    .method private hidebysig static void Main(string[] args) cil managed  
    {      
        .entrypoint    
        
    // Code Size: 15 byte(s)     
       .maxstack 1     
       .locals (       
         EnumerationFaq.Alignment alignment1)     
       L_0000: ldc.i4.
    1     
       L_0001: stloc.
    0     
       L_0002: ldloc.
    0      
       L_0003: box EnumerationFaq.Alignment   
       
    // 调用static void Print(Enum e);    
       L_0008: call void EnumerationFaq.Program::Print([mscorlib]System.Enum)   
       L_000d: nop     
       L_000e: ret  
    }  
  • 相关阅读:
    Hadoop 2.2.0单节点的伪分布集成环境搭建
    CentOS系统中出现错误--SSH:connect to host centos-py port 22: Connection refused
    JUnit 5和Selenium基础(三)
    JUnit 5和Selenium基础(二)
    JUnit 5和Selenium基础(一)
    如何对N个接口按比例压测
    性能测试中标记每个请求
    初学者的API测试技巧
    Web安全检查
    Groovy重载操作符
  • 原文地址:https://www.cnblogs.com/purplefox2008/p/1620104.html
Copyright © 2011-2022 走看看