C# 枚舉基礎篇

來源:互聯網
上載者:User

Q:在C#裡,我們如何表達枚舉類型?

A:你可以使用enum關鍵字(keyword)來聲明一個枚舉類型(enum type):

//Code #1public 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  
}  

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.