閱讀目錄基本用法高級用法 本文主要是我在項目中對C#枚舉的使用心得,如有不足的地方歡迎您指出。一、基本介紹 枚舉是由一組特定常量構成的一組數據結構,是值類型的一種特殊形式,當需要一個由指定常量集合組成的數據類型時,使用枚舉類型。枚舉聲明可以顯式地聲明 byte、sbyte、short、us
閱讀目錄
本文主要是我在項目中對C#枚舉的使用心得,如有不足的地方歡迎您指出。
一、基本介紹
枚舉是由一組特定常量構成的一組數據結構,是值類型的一種特殊形式,當需要一個由指定常量集合組成的數據類型時,使用枚舉類型。枚舉聲明可以顯式地聲明 byte、sbyte、short、ushort、int、uint、long 或 ulong 類型作為對應的基礎類型。沒有顯式地聲明基礎類型的枚舉聲明意味著所對應的基礎類型是 int。
在代碼中使用枚舉,可以將以前笨拙的代碼變得優雅簡單,更加直觀,方便記憶。
枚舉在什麼地方適用呢?一條普遍規則是,任何使用常量的地方,例如目前用 switch 代碼切換常量的地方。如果只有單獨一個值(例如,鞋的最大尺寸,或者籠子中能裝猴子的最大數目),則還是把這個任務留給常量吧。但是,如果定義了一組值,而這些值中的任何一個都可以用於特定的數據類型,那麼將枚舉用在這個地方最適合不過。
例1:一個欄位表示類型。你可以使用整數1、2、3代表原創、轉載、翻譯三種類型。這種表示法可以使用,但它不直觀。此時應該使用枚舉。
例2:表示星期的SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY,SATURDAY, 就是應該定義成一個枚舉。
1、 對於沒有賦值的枚舉類型,聲明的第一個枚舉成員它的默值為零。以後的枚舉成員值是將前一個枚舉成員(按照文本順序)的值加1得到的。
2 、允許多個枚舉成員有相同的值。沒有顯示賦值的枚舉成員的值,總是前一個枚舉成員的值+1。
三、使用方法
.NET中的枚舉我們一般有兩種常見用法,一是表示唯一的元素序列,例如一周里的各天,訂單狀態,文章類型等;還有就是用來表示多種複合的狀態,例如表示許可權,因為可同時有多個不同許可權。
1、基本用法
這裡用文章類型來舉例,就不過多的說明瞭,直接用程式說話吧,代碼中的 [Description("原創")],會在後面進行說明。
C# Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
using System; using System.ComponentModel; using System.Reflection; using System.Collections.Generic; using System.Data.SqlClient; using System.Data; namespace MyLaboratory { /// <summary> /// 訂單狀態的枚舉類型 /// </summary> public enum ArticleType { /// <summary> /// 原創 /// </summary> [Description("原創")] Original = 1, /// <summary> /// 翻譯 /// </summary> [Description("翻譯")] Translate = 2, /// <summary> /// 轉載 /// </summary> [Description("轉載")] Reproduced = 3 } /// <summary> /// 文章類,此處簡化了,為了演示只設計了三個欄位 /// </summary> public class Article { private int _id; private string _title = ""; private ArticleType _type; /// <summary> /// 文章編號 /// </summary> public int ID { get { return _id; } set { _id = value; } } /// <summary> /// 文章標題 /// </summary> public string Title { get { return _title; } set { _title = value; } } /// <summary> /// 文章類型 /// </summary> public ArticleType Type { get { return _type; } set { _type = value; } } /// <summary> /// 添加一篇文章 /// </summary> /// <returns></returns> public bool Add() { //影響的行數 int EffectRow = 0; using (SqlConnection conn = new SqlConnection("資料庫連接串")) { SqlCommand cmd = new SqlCommand("INSERT INTO Article(ID,Title,Type) VALUES(@ID,@Title,@Type)", conn); cmd.Parameters.Add(new SqlParameter("@ID", this._id)); cmd.Parameters.Add(new SqlParameter("@Title", this._title)); cmd.Parameters.Add(new SqlParameter("@Type", this._type)); //枚舉屬性直接使用即可 conn.Open(); EffectRow = cmd.ExecuteNonQuery(); } return EffectRow == 1 ? true : false; } /// <summary> /// 獲取文章的詳情 /// </summary> public void GetInfo() { //從資料庫中讀取訂單信息 DataSet ds = new DataSet(); using (SqlConnection conn = new SqlConnection("資料庫連接串")) { SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Article WHERE ID=@ID", conn); da.SelectCommand.Parameters.Add(new SqlParameter("@ID", this._id)); conn.Open(); da.Fill(ds, "Article"); } if (ds != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0) { //將字元串轉化成枚舉類型 this._type = (ArticleType)Enum.Parse(typeof(ArticleType), ds.Tables[0].Rows[0]["Type"].ToString()); this._title = ds.Tables[0].Rows[0]["Title"].ToString(); } } } } |
2、高級用法
為了說明表示多種組合狀態,拿用戶的許可權來舉例。此時需要在枚舉上加[Flags]特性來標記位域。
C# Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/// <summary> /// 許可權枚舉 /// </summary> [Flags] public enum Permission { [Description("未知")] Unknown = 0,//也可以寫成0x00或0 [Description("創建")] Create = 1 << 0,//0x01或1 [Description("讀取")] Read = 1 << 1,//0x02或2 [Description("修改")] Update = 1 << 2,//0x04或4 [Description("刪除")] Delete = 1 << 3//0x08或8 } |
註意加了[Flags]特性後有三種寫法,一種是使用<<符號,第二種是0x01,還有一種是直接寫0,1,2,4,8...,一般來說是2的n次方來表示。
C# Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//1,給用戶創建,讀取,修改和刪除的許可權 var permission = Permission.Create | Permission.Read | Permission.Update | Permission.Delete; //2,去掉用戶的修改和刪除許可權 //permission = permission ^ Permission.Update;這種寫法有bug,如果重覆執行又加回去了 permission = permission & ~Permission.Update; permission = permission & ~Permission.Delete; //3,給用戶加上修改的許可權 permission = permission | Permission.Update; //4,判斷用戶是否有創建的許可權 var isCreate = (permission & Permission.Create) != 0; //或者var isCreate =(permission & Permission.Create)== Permission.Create |
這時permission枚舉的值將變成 0+1+4=5,它的ToString()將變成"Permission.Create , Permission.Read,Permission.Update"
這裡我們可以解釋為什麼第五個值Delete是8.而不能為5。也就是說它的值不應該是前幾項值的複合值。一個比較簡單的方法就是用2的n次方來依次為每一項賦值,例如 1,2,4,8,16,32,64.....
在資料庫中可以這樣來判斷:
AND (@permission IS NULL OR (permission & @permission) =@permission)
四、擴展用法 下麵來擴展一下枚舉的用法,講解一下使用枚舉帶來的另外兩個額外紅利。
1、獲取枚舉的擴展屬性 前面例子中的文章類(Article),其中屬性(Type)如果不使用枚舉,而是分別對應Int數值1、2、3,那麼在文章列表(WEB頁面)中顯示類型一般如下處理。 ASP.NET MVC Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
@{ if (ViewBag.List != null) { List<MyLaboratory.Article> list = (List<MyLaboratory.Article>)ViewBag.list; foreach (Article article in list) { string TypeName = ""; if (article.Type == 1) { TypeName = "原創"; } else if (article.Type == 2) { TypeName = "翻譯"; } else if (article.Type == 3) { TypeName = "轉載"; } <tr> <td>@article.ID</td> <td>@article.Title</td> <td>@TypeName</td> </tr> } } } |
按上面的代碼,如果類型進行增加或刪除,那上面這段代碼也需要修改,如果有多個頁麵包含類似的代碼,那進行一次修改,代碼的維護量還是挺大的,還有漏改的風險。如果使用枚舉,則可以通過Description來給枚舉增加擴展說明,在顯示枚舉的地方直接顯示擴展說明,代碼如下:
1)、在定義枚舉值時,加入Description擴展屬性,通過添加GetEnumDescription方法來獲取枚舉的擴展屬性,我把GetEnumDescription放到了一個公共類(Utility)中,這樣方便調用。 C# Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class Utility { /// <summary> /// 獲取一個枚舉值的中文描述 /// </summary> /// <param name="obj">枚舉值</param> /// <returns></returns> public static string GetEnumDescription(Enum obj) { FieldInfo fi = obj.GetType().GetField(obj.ToString()); DescriptionAttribute[] arrDesc = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); return arrDesc[0].Description; } } |
2)、調用的代碼如下(ASP.NET MVC)
ASP.NET MVC Code