摘要:.NET中的枚舉分為簡單枚舉和標誌枚舉,這次主要總結一下標誌枚舉適用條件,以及它的使用方法,併在文章的最後列舉枚舉使用的一些規範。 在剛接觸.NET的枚舉時,只用簡單的枚舉,對於標記枚舉,只知道是在枚舉類型加上 特性,然後給枚舉值賦予十六進位的值,並且書中還特別明確規定值必須是以2的指數才可以 ...
摘要:.NET中的枚舉分為簡單枚舉和標誌枚舉,這次主要總結一下標誌枚舉適用條件,以及它的使用方法,併在文章的最後列舉枚舉使用的一些規範。
在剛接觸.NET的枚舉時,只用簡單的枚舉,對於標記枚舉,只知道是在枚舉類型加上Flags
特性,然後給枚舉值賦予十六進位的值,並且書中還特別明確規定值必須是以2的指數才可以,這樣可以方便在使用時,對多個枚舉值進行或運算。隨著對.NET的瞭解不斷的深入,現在終於明白了標誌枚舉的適用場合以及它的使用方法,因此在這裡總結一下。
標誌枚舉的適用條件
在System.Drawing
命令空間中有一個FontStyle
標誌枚舉,專門用來設置字體的風格,有Blod、Italic、Regular、Strikeout、Underline這5種風格。當然我們需要設置字體為單個一種風格時,那麼FontStyle枚舉的用法和簡單枚舉沒什麼區別,比如,我們需要把字體風格為設置為粗體,代碼如下:
System.Drawing.Font font = new System.Drawing.Font("宋體",12,FontStyle.Bold);
但是,如果我們需要設置字體的風格為粗體的同時還要需要斜體和下劃線呢?對於這種情況,簡單枚舉就不適用了,這就必須使用標誌枚舉的進行組合才能辦到了,代碼如下:
System.Drawing.Font font = new System.Drawing.Font("宋體",12, FontStyle.Bold|FontStyle.Italic|FontStyle.Underline);
通過這樣的組合就能夠達到我們想要的效果。
自定義FontStyle標誌枚舉,一探究竟
下麵我們自己設計一個FontStyle
,看看它的內部是如何實現的。代碼如下:
[Flags]
public enum FontStyle: byte
{
Bold=0x01,
Italic = 0x02,
Regular = 0x04,
Strikeout=0x08,
Underline=0x10,
}
上面的定義了一個FontStyle
枚舉,該枚舉繼承byte
類型,通過加上Flags
特性,使它成為標誌枚舉,並且為每一個枚舉值賦值一個十六進位的值,每一個值都是2的指數值。下麵將詳細解釋一些為什麼要使用2的指數來進行賦值。
為什麼使用2的指數值對枚舉進行賦值
首先我們要明白,二進位的或運算,或運行無非就4種情況,
0|0=0; 0|1=1; 1|0=1; 1|1=1;
那麼二進位10101010和01010101進行或運算就等於11111111,明白了二進位的或運算,再仔細想想,一個位元組8位二進位,可以代表0-255。其中1,2,4,8,16,32,64,128是2的指數,分別代表的二進位的00000001,00000010,00000100,00001000,00010000,00100000,01000000,10000000,它們的每個取值剛好是將8位中的某一位設為1。那麼這8個值以及它們任意組合(或運算)剛好能夠代表種情況(其中是單個枚舉,其他都是組合),對標誌枚舉使用2的指數值進行賦值,能夠進行任意的組合,並且任意組合後的值不會有重覆。
這就是為什麼要使用2的指數值對標誌枚舉進行複製的原因。順便這裡再多說一句,賦值的時候為什麼不用10進位,而是用16進位的表示法,前面我們分析了,標誌枚舉的組合最後都將進行二進位的或運算,而我們在賦值的時候用16進位會更加表現明顯,因為每一個16進位的數值,剛好代表二進位4個位,所以兩個16進位的數就能代表一個位元組,比如0x11,我們化為二進位,只需要對兩個1分別換算4個二進位位就行了,1=0001,所以0x11就代表00010001,如果用十進位17來表示,就沒那麼輕易地看出它的二進位表示。
如何處理組合枚舉
當我們把標誌枚舉賦值為2的指數值之後,我們就可以組合的使用這些枚舉值,以期達到我們想要的效果,那麼在函數設計中,我們是如何來處理傳入進來的枚舉組合值呢?其實也非常簡單,正是因為他們任意的組合都不會重覆,因此每一個數值可以代表其中的一個枚舉值或者是一個組合,比如,FontStyle.Bold|FontStyle.Italic|FontStyle.Underline
這個組合所代表的數值就位0x01|0x02|0x10=19.
下麵設計一個函數處理傳入進來的枚舉值。代碼如下:
static void Test(FontStyle fontStyle)
{
switch ((byte)fontStyle)
{
case 1:
Console.WriteLine("Bold");
break;
case 2:
Console.WriteLine("Italic");
break;
case 3:
Console.WriteLine("Bold&Italic");
break;
case 4:
Console.WriteLine("Regular");
break;
case 6:
Console.WriteLine("Regular&Italic");
break;
case 8:
Console.WriteLine("Strikeout");
break;
case 9:
Console.WriteLine("Strikeout&Bold");
break;
case 10:
Console.WriteLine("Strikeout&Italic");
break;
case 11:
Console.WriteLine("Strikeout&Italic&Bold");
break;
case 16:
Console.WriteLine("Underline");
break;
case 19:
Console.WriteLine("Bold&Italic&Underline");
break;
//else
}
}
因為枚舉在CLR內部實現可以看做是數值類型。在Test函數內部我們需要用Switch去判斷傳入的枚舉值,確定是否單個枚舉還是組合後的值,並對其做出相應的處理。下麵給出測試代碼。
static void Main(string[] args)
{
Test(FontStyle.Bold);
Test(FontStyle.Strikeout|FontStyle.Italic);
Test(FontStyle.Bold|FontStyle.Italic|FontStyle.Underline);
Console.ReadKey();
}
測試結果如下:
總結一些設計枚舉的規範
- 簡單枚舉的命名採用單數形式。
- 不要使用Enum、Flag、Flags作為枚舉類型的尾碼。
- 不要給枚舉值的命名加上枚舉類型名首碼,比如
FontStyleBlod
這樣是不規範的。 - 使用枚舉代替一些固定的常量集合。
- 使用枚舉作為參數、屬性、返回值,來保證該API是強類型的API。
- 考慮給枚舉提供一個
None=0
的枚舉值。 - 給標誌枚舉賦值為2的指數值。