有關(guān)C#枚舉的問答集錦:有關(guān)賦值
本文繼續(xù)介紹C#枚舉的常見問題與答案。
Q:我留意到Code #02中的
.field public static literal Aligment Center = int32(0x00000001)
該語句明顯是整數(shù)賦值,這是否說明C#枚舉類型實(shí)質(zhì)上是整數(shù)類型?
A:這說明枚舉類型與整數(shù)類型的確有一定的關(guān)系。事實(shí)上,每一個(gè)枚舉類型都有與之相對(duì)應(yīng)的整數(shù)類型,我們稱該整數(shù)類型為底層類型(underlying type),默認(rèn)的情況下使用,.NET使用System.Int32。當(dāng)然,你可以手動(dòng)將其指定為其他的整數(shù)類型:
- // Code #09
 - public enum Alignment : byte
 - {
 - Left,
 - Center,
 - Right
 - }
 
注意,能被指定為枚舉的底層類型的只能是如下所列的整數(shù)類型:byte, sbyte, short, ushort, int, uint, long, ulong。
--------------------------------------------------------------------------------
Q:為何我們需要指定枚舉類型的底層類型?
A:你完全可以讓它接受默認(rèn)的底層類型。請(qǐng)留意Code #08,你完全找不到“Center”這個(gè)字眼,然而在C#代碼中,它卻是存在的,為什么呢?這是因?yàn)榇a在編譯的時(shí)候,編譯器把枚舉類型轉(zhuǎn)換為與之對(duì)應(yīng)的底層類型的數(shù)值來處理。Code #08的L_0000實(shí)際上就是把類型為System.Int32的數(shù)值1推入堆棧,而不是把“Center”推入堆棧。事實(shí)上,底層類型說明了如何為枚舉類型分配空間,不同的底層類型所占用的資源不同,大概當(dāng)你在受限系統(tǒng)上進(jìn)行開發(fā)的話,你就可能需要注意一下了。
--------------------------------------------------------------------------------
C#枚舉的賦值
Q:枚舉成員的值是怎樣規(guī)定的?
A:如果你沒有手動(dòng)指定成員的值的話,從上往下看,各成員的值為:0, 1, 2, ...。說罷了,就是一個(gè)非負(fù)整數(shù)等差數(shù)列,其初值為0,步長(zhǎng)為1。例如:
- // Code #10
 - public enum Alignment
 - {
 - Left, // 0
 - Center, // 1
 - Right // 2
 - }
 
--------------------------------------------------------------------------------
Q:如果我有手動(dòng)指定某些成員的值呢?
A:那么被賦值的成員的值就是你所指定的值。當(dāng)然,無論你是否手動(dòng)指定枚舉成員的值,遞增步長(zhǎng)都不會(huì)變,總是為1。為了測(cè)試你是否理解,請(qǐng)說出下面枚舉個(gè)成員的值以及你的判斷理由(請(qǐng)用人腦而不是電腦來運(yùn)行以下代碼):
- // Code #11
 - public enum DriveType : sbyte
 - {
 - CDRom,
 - Fixed = -2,
 - Network,
 - NoRootDirectory = -1,
 - Ram,
 - Removable = Network * NoRootDirectory,
 - Unknown
 - }
 
--------------------------------------------------------------------------------
Q:我們?nèi)绾潍@取枚舉成員的值,無論成員是否被手動(dòng)賦值?
A:你可以使用System.Enum的
- public static Array GetValues(Type enumType);
 
該方法返回一個(gè)包含所有枚舉成員的數(shù)組:
- // Code #12
 - // See Code #01 for Alignment.
 - public static void Main()
 - {
 - Alignment[] alignments = (Alignment[])Enum.GetValues(typeof(Alignment));
 - Console.WriteLine("Wanna see the values of Alignment's menbers?");
 - foreach (Alignment a in alignments)
 - Console.WriteLine("{0:G} = {0:D}", a);
 - }
 - // Output:
 - // Wanna see the values of Alignment's menbers?
 - // Left = 0
 - // Center = 1
 - // Right = 2
 
--------------------------------------------------------------------------------
Q:如果我只需要其中某些枚舉成員的值呢?
A:那么你可以把枚舉轉(zhuǎn)換為IConvertible接口,再調(diào)用對(duì)應(yīng)的方法:
- // Code #12
 - // See Code #01 for Alignment.
 - public static void Main()
 - {
 - IConvertible ic = (IConvertible)Alignment.Center;
 - int i = ic.ToInt32(null);
 - Console.WriteLine("The value of Alignment.Center is {0}.", i);
 - }
 - // Output:
 - // The value of Alignment.Center is 1.
 
--------------------------------------------------------------------------------
Q:為什么需要手動(dòng)指定枚舉成員的值?
A:一般情況下,使用默認(rèn)的賦值規(guī)則就足夠了,但某些情況下,為枚舉成員指定一個(gè)與實(shí)際情況(模型)相符的值可能更有意義,這要視你具體所建的模型而定。
還是讓我們來一個(gè)實(shí)際的例子:
- // Code #13
 - public enum CustomerKind
 - {
 - Normal = 90,
 - Vip = 80,
 - SuperVip = 70,
 - InActive = 100
 - }
 - public class Customer
 - {
 - public readonly CustomerKind Kind;
 - private double m_Payment;
 - public double Payment
 - {
 - return m_Payment * (int)Kind / 100;
 - }
 - // Code here
 - }
 
我為枚舉CustomerKind的每個(gè)成員都賦了一個(gè)特定的值,該值其實(shí)就是顧客購物折扣百分率。而在Customer類中,Payment屬性就通過強(qiáng)類型轉(zhuǎn)換來獲取枚舉成員的值(也就是購物折扣率),并用于貨款計(jì)算。從這里可以看出,獲取枚舉成員的值還可以通過強(qiáng)類型轉(zhuǎn)換方式。
--------------------------------------------------------------------------------
Q:既然枚舉類型可以強(qiáng)制轉(zhuǎn)換為整數(shù),那么整數(shù)是否也可以強(qiáng)制轉(zhuǎn)換為枚舉類型?
A:答案是肯定的。
- // Code #14
 - // See Code #01 for Alignment.
 - Alignment a = (Alignment)1;
 
但這種機(jī)制可能使你遇到一些麻煩:
- // Code #15
 - // See Code #01 for Alignment.
 - class Program
 - {
 - static void Main()
 - {
 - Foo((Alignment)12345);
 - }
 - static void Foo(Alignment a)
 - {
 - // Code here
 - }
 - }
 
你無法避免有人進(jìn)行這樣的惡作劇??!
--------------------------------------------------------------------------------
Q:那么是否有辦法對(duì)付這些惡作劇的人?
A:Sure!我們總不能假設(shè)人人都那么守規(guī)矩,所以,我們需要System.Enum的
- public static bool IsDefined(Type enumType, object value);
 
現(xiàn)在我們把Code #15的Foo方法改進(jìn)一下:
- // Code #16
 - // See Code #01 for Alignment.
 - static void Foo(Alignment a)
 - {
 - if (!Enum.IsDefined(typeof(Alignment), a))
 - throw new ArgumentException("DO NOT MAKE MISCHIEF!");
 - // Code here
 - }
 
這樣,惡作劇的人將會(huì)收到一個(gè)警告(異常消息)。當(dāng)然,我們不排除有人是由于一時(shí)大意才造成這樣的“惡作劇”,那么IsDefined方法同樣可以幫助你處理好這些情況。
--------------------------------------------------------------------------------
Q:我認(rèn)為我們還可以使用條件判斷語句來處理這種情況:
- // Code #17
 - // See Code #01 for Alignment.
 - static void Foo(Alignment a)
 - {
 - if (a != Alignment.Left &&
 - a != Alignment.Center &&
 - a != Alignment.Right)
 - throw new ArgumentException("DO NOT MAKE MISCHIEF!");
 - // Code here
 - }
 
或者
- // Code #18
 - // See Code #01 for Alignment.
 - static void Foo(Alignment a)
 - {
 - switch(a)
 - {
 - case Alignment.Left:
 - Console.WriteLine("Cool~");
 - break;
 - case Alignment.Center:
 - Console.WriteLine("Well~");
 - break;
 - case Alignment.Right:
 - Console.WriteLine("Good~");
 - break;
 - default:
 - Console.WriteLine("DO NOT MAKE MISCHIEF!");
 - break;
 - }
 - }
 
A:你絕對(duì)可以這樣做!事實(shí)上,如果你處于以下情況之一的話:
1. Alignment枚舉代碼不會(huì)被修改 
2. 你不希望使用Alignment枚舉新增的特性
那么我會(huì)推薦使用你的處理方式。而且,你還可以為自己的代碼定義一個(gè)這樣的方法:
- // Code #19
 - // See Code #01 for Alignment.
 - public static bool IsAlignment(Alignment a)
 - {
 - switch(a)
 - {
 - case Alignment.Left:
 - return true;
 - case Alignment.Center:
 - return true;
 - case Alignment.Right:
 - return true;
 - default:
 - return false;
 - }
 - }
 
這個(gè)方法比起IsDefine方法高效多了。
--------------------------------------------------------------------------------
以上就總結(jié)了一些C#枚舉賦值的相關(guān)問答。
【編輯推薦】















 
 
 
 
 
 
 