本文來源于網頁設計愛好者web開發社區http://www.html.org.cn收集整理,歡迎訪問。
c# 語言規范 
14.3 枚舉成員枚舉類型聲明的體用于定義零個或多個枚舉成員,這些成員是該枚舉類型的命名常數。任意兩個枚舉成員不能具有相同的名稱。 
enum-member-declarations:(枚舉成員聲明:) 
enum-member-declaration(枚舉成員聲明)
enum-member-declarations , enum-member-declaration(枚舉成員聲明 , 枚舉成員聲明) 
enum-member-declaration:(枚舉成員聲明:) 
attributesopt identifier(屬性可選 標識符)
attributesopt identifier = constant-expression(屬性可選 標識符 = 常數表達式) 
每個枚舉成員均具有相關聯的常數值。此值的類型就是包含了它的那個枚舉的基礎類型。每個枚舉成員的常數值必須在該枚舉的基礎類型的范圍之內。示例
enum color: uint
{
 red = -1,
 green = -2,
 blue = -3
} 
產生編譯時錯誤,原因是常數值 -1、-2 和 –3 不在基礎整型 uint 的范圍內。
多個枚舉成員可以共享同一個關聯值。示例
enum color 
{
 red,
 green,
 blue,
 max = blue
}
顯示一個枚舉,其中的兩個枚舉成員(blue 和 max)具有相同的關聯值。
一個枚舉成員的關聯值或隱式地、或顯式地被賦值。如果枚舉成員的聲明中具有“常數表達式”初始值設定項,則該常數表達式的值(它隱式轉換為枚舉的基礎類型)就是該枚舉成員的關聯值。如果枚舉成員的聲明不具有初始值設定項,則它的關聯值按下面規則隱式地設置: 
如果枚舉成員是在枚舉類型中聲明的第一個枚舉成員,則它的關聯值為零。 
否則,枚舉成員的關聯值是通過將前一個枚舉成員(按照文本順序)的關聯值加 1 得到的。這樣增加后的值必須在該基礎類型可表示的值的范圍內;否則,會出現編譯時錯誤。 
示例
using system;
enum color
{
 red,
 green = 10,
 blue
}
class test
{
 static void main() {
 console.writeline(stringfromcolor(color.red));
 console.writeline(stringfromcolor(color.green));
 console.writeline(stringfromcolor(color.blue));
 }
 static string stringfromcolor(color c) {
 switch (c) {
 case color.red: 
 return string.format("red = {0}", (int) c);
 case color.green:
 return string.format("green = {0}", (int) c);
 case color.blue:
 return string.format("blue = {0}", (int) c);
 default:
 return "invalid color";
 }
 }
}
輸出枚舉成員名稱和它們的關聯值。輸出為:
red = 0
green = 10
blue = 11
原因如下: 
枚舉成員 red 被自動賦予零值(因為它不具有初始值設定項并且是第一個枚舉成員)。 
枚舉成員 green 被顯式賦予值 10。 
枚舉成員 blue 被自動賦予比文本上位于它前面的成員大 1 的值。 
枚舉成員的關聯值不能直接或間接地使用它自己的關聯枚舉成員的值。除了這個循環性限制外,枚舉成員初始值設定項可以自由地引用其他的枚舉成員初始值設定項,而不必考慮它們所在的文本位置的排列順序。在枚舉成員初始值設定項內,其他枚舉成員的值始終被視為屬于所對應的基礎類型,因此在引用其他枚舉成員時,沒有必要使用強制轉換。
示例
enum circular
{
 a = b,
 b
}
產生編譯時錯誤,因為 a 和 b 的聲明是循環的。a 顯式依賴于 b,而 b 隱式依賴于 a。
枚舉成員的命名方式和作用范圍與類中的字段完全類似。枚舉成員的范圍是包含了它的枚舉類型的體。在該范圍內,枚舉成員可以用它們的簡單名稱引用。在所有其他代碼中,枚舉成員的名稱必須用它的枚舉類型的名稱限定。枚舉成員不具有任何聲明可訪問性,如果一個枚舉類型是可訪問的,則它所含的所有枚舉成員都是可訪問的。
--------------------------------------------------------------------------------
向 microsoft 發送有關此主題的反饋
© microsoft corporation。保留所有權利。
先來看這段nunit測試代碼,我們希望用反射機制在運行時訪問一個對象的枚舉類型的域或屬性:
 
[testfixture]
public class paymentinfo
{
 public enum paymenttype
 {
 cash, creditcard, check
 }
 public paymenttype type;
 public void test()
 {
 paymentinfo payment = new paymentinfo();
 payment.type = paymenttype.cash;
 system.reflection.fieldinfo enumfield = gettype().getfield("type");
 int paymenttypeint32;
 paymenttypeint32 = (int)enumfield.getvalue(payment);
 assert.areequal((int)paymenttype.cash, paymenttypeint32);
 enumfield.setvalue(payment, paymenttypeint32);
 assert.areequal(paymenttype.cash, payment.type);
 }
}
 
實際上運行測試時發現在標紅的這行上拋出一個異常:“對象類型無法轉換為目標類型”。究其原因,原來是因為clr的反射機制不允許枚舉類型與整數類型之間隱式轉換。不過c#編譯器還是允許我們通過強制類型轉換的語法來進行兩者間的顯式轉換。
 
在這個測試中,使之通過的辦法其實非常簡單:把劃線部分強制轉換為枚舉類型即可,如:(paymenttype)paymenttypeint32。可問題是:在運行時如何動態轉換類型呢?比如說我在寫elegantdal的時候,需要將從數據庫讀出的一個類型為int的數值寫入到要返回的對象的一個枚舉型字段中,此時我只有fieldinfo、columnvalue和resultobject,然而寫成fieldinfo.setvalue(resultobject, columnvalue)就會出現前面提到的錯誤,可是我又只有一個運行時的type信息(fieldinfo.fieldtype),我又不能寫成fieldinfo.setvalue(resultobject, (fieldinfo.fieldtype)columnvalue)……
 
只好將這種情況列為一個特例處理,而我們的救兵則是enum.toobject()方法——你知道有更好的方法解決這個問題嗎?
 枚舉類型是c#中又一種輕量級的值類型,c#用枚舉來表達一組特定的值的集合行為,比如windows窗體可選的狀態,按鈕控件的風格等。下面的程序偽碼展示了典型的枚舉用法:
public enum writingstyle
{ 
 classical,
 modern,
 elegant,
}
class essay
{
 public void write(writingstyle writingstyle)
 {
 switch (writingstyle)
 {
 case writingstyle.classical:
 // 古典的寫作風格
 break;
 case writingstyle.modern:
 // 現代的寫作風格
 break;
 case writingstyle.elegant:
 // 典雅的寫作風格
 break;
 default:
 throw(new system.argumentexception("invalid writing style"));
 }
 }
}
 注意上面的枚舉符號classical, modern, elegant之間用逗號“,”而不是分號“;”來分隔。其中最后一個枚舉值elegant之后可以省去逗號分隔符。
 和結構一樣,c#中的枚舉不允許也有自己的繼承父類system.enum,同樣的,枚舉不能被繼承,也沒有abstract一說。system.enum類為枚舉類型提供了很多好用的功能操作。比如我們可以通過getname方法得到我們聲明枚舉值的字符串符號表示。下面的例子顯示了一些比較常用的操作:
using system;
public enum writingstyle
{ 
 classical,
 modern,
 elegant,
}
class test
{
 public static void main()
 {
 writingstyle dw=writingstyle.modern;
 console.writeline(enum.getname(typeof(writingstyle),dw));
 console.writeline(dw.tostring());
 console.writeline(enum.getunderlyingtype(typeof(writingstyle)));
 } 
}
 其中的最后一行輸出了system.int32,這是怎么回事?我們知道int是system.int32的簡寫形式,難道我們的writingstyle枚舉類型和整數int類型有什么關系嗎?
是的,c#的枚舉和整數值之間嚴格區分,比如我們就不能在上面的代碼中作dw=1類似的賦值。但每個枚舉值卻的的確確都有一個整數類型的數值相對應,而且可以轉換,只不過這種轉換必須用明晰的轉型語法來表達。我們知道在c#中整數類型有byte, sbyte, short, ushort, int, uint, long ,ulong共八種,那么c#的枚舉值對應的是哪一種整數類型呢?它關系到我們的枚舉類型能夠容納的枚舉值的數量。實際上c#枚舉類型支持這八種整數類型的任何一種,根據我們的需要,可以在聲明枚舉類型的時候來指定,如“public enum writingstyle :byte”就指定了它的枚舉值的整數類型為byte。該類型可以通過上面所述的enum.getunderlyingtype方法來獲得。如果不明確指定,c#將默認采用int類型作為枚舉數值的類型。既然枚舉值實際上也是一種整數值,那么它的大小呢?讀者將下面的代碼加在上面的main函數內,就可看到結果了。
 foreach(object obj in enum.getvalues(typeof(writingstyle)))
 {
 console.writeline(obj.tostring() +" : "+(int)obj);
 }
上面的代碼將產生以下輸出:
classical : 0
modern : 1
elegant : 2
可以看到,c#默認地從0起為我們的枚舉值賦了一個隱含的值。當然,我們也可以自己為枚舉值指定數值:
public enum writingstyle
{ 
 classical=0,
 modern=10,
 elegant=100,
}
我們甚至可以象下面這樣,前提是我們必須保證編譯時能夠計算出他們各自的數值。
public enum writingstyle
{ 
 classical=0,
 modern=10+classical,
 elegant=10+modern,
}
枚舉值也擁有象整數那樣的比較,邏輯,算術等操作行為,看下面的例子:
using system;
public enum writingstyle
{ 
 classical=0,
 modern=10+classical,
 elegant=10+modern,
}
class test
{
 public static void main()
 {
 writingstyle dw=writingstyle.modern;
 console.writeline(dw+10);
 console.writeline(dw+9);
 } 
}
當計算出來的數值等于某個枚舉值的實際大小,那么顯示的是該枚舉值的符號名稱,否則顯示的將是整數值。