主頁 > .NET開發 > 細說列舉

細說列舉

2020-09-18 11:01:13 .NET開發

列舉是 C# 中最有意思的一部分,大部分開發人員只了解其中的一小部分,甚至網上絕大多數的教程也只講解了列舉的一部分,那么,我將通過這篇文章向大家具體講解一下列舉的知識,我將從大家都了解的部分開始講解,然后再講解大家所不知道的或者了解很少的部分,

零、基礎知識

列舉是由開發人員宣告的一種 值型別 ,它在編譯時就宣告了一種 具名常量值 ,使用列舉可以使我們的代碼簡單易讀,我們先來看一下兩個代碼段:

// 代碼段 1
void Method(int country)
{
    switch (country)
    {
        case 0:
            // more code
            break;
        case 1:
            // more code
            break;
        case 2:
            // more code
            break;
        case 3:
            // more code
            break;
        default:
            // more code 
            break;
    }
}

// 代碼段 2
void Method(Country country)
{
    switch (country)
    {
        case Country.CN:
            // more code
            break;
        case Country.JP:
            // more code
            break;
        case Country.UK:
            // more code
            break;
        case Country.USA:
            // more code
            break;
        default:
            // more code 
            break;
    }
}

從上面的兩個代碼段我們可以看到兩者有明顯的區別,第一段代碼中的 case 值我們幾乎完全不知道代表了什么是什么意思,但是第二段代碼我們使用了列舉,通過 case 值馬上就可以知道所要表達的意思,同樣利用列舉值替代布林值也可以改善代碼的可讀性,例如我們要開發控制臺燈打開關閉的程式,代碼可以這么寫 LightOperating(True) ,但是這種代碼我們無法看出具體要干什么,現在我們將代碼改動一下 LightOperating(Light.On) ,經過修改代碼就很容易看出所要表達的意思,

  1. 列舉定義與取值
    定義列舉有兩種方式,分別是普通方式和自定義方式,不管使用哪種方式都需要用的關鍵字 enum 來標識這個型別為列舉型別,并且列舉值都是作為整數常量來實作的,下面我們就來看一下這兩種方式怎么定義列舉的,普通方式是我們經常用到的,也是默認的方式,這種方式很簡單,代碼如下:

    enum Country
    {
        CN,
        UK,
        JP,
        USA
    }
    

    在上面的代碼段中我們定義了一個國家列舉,第一個列舉值對應的整數常量是 0 ,第二個列舉值對應的整數常量是 1 ,以此類推后面的列舉值分別對應的整數常量是 23 ,但是在部分情況下我們需要自定義列舉值對應的整數常量,這個時候我們就需要用到自定義的方式,自定義方式又稱為為列舉值顯式賦值,它的方法如下所示:

    enum Country
    {
        CN = 3,
        UK,
        JP = 70,
        USA = 67
    }
    

    我們在代碼中將第一個列舉值對應的整數常量設定為了 3 ,這時第二個列舉值的整數常量就不是 1 了,而是 4 ,因為當列舉值沒有顯示賦值時,將會按照上一個列舉值對應的整數值加 1 來作為自己本身對應的整數值,最后兩個列舉值因為顯式賦值了因此對應的整數值就是所賦值的數值,
    列舉取值也很簡單,只需要 列舉名.列舉值 即可,例如 Country.UK

    Tip:這里我提幾點建議:

    • 列舉值的名稱不應包含列舉名稱;
    • 列舉名稱應以單數的形式出現(除了屬性),
  2. 列舉的型別
    到目前為止我們定義列舉型別使用的基礎型別 int 型別,但是列舉不僅僅可以使用 int 型別,還可以使用除了 char 型別之外的所有基礎型別,我們可以使用繼承語法來指定其他型別,

    enum Country:short
     {
         CN = 3,
         UK,
         JP = 70,
         USA = 67
     }
    

    上面代碼中我們顯式定義了列舉所使用的基礎型別為 short ,這里雖然使用了繼承語法但是并沒有建立繼承關系,所有的列舉基類都是 System.Enum ,這些類都是密封類,無法從現有的列舉型別派生出新的成員,
    對于列舉型別的變數,值不限于宣告中命名的值,因此值能轉換成基礎型別,那么就能轉換為列舉型別,之所以這么設計是因在以后的 API 中有很大的可能在不破換老版本的同時為列舉添加新的值,但是這其中也存在一個缺陷,列舉允許在運行時分配未知的值,對于這一點我們在開發時需要考慮到,并且在后期向列舉中添加新的列舉值時應將其添加到所有列舉值的后面,或者顯示指定列舉值對應的數值,這樣才能避免因添加新值導致列舉型別中的列舉值對應的數值改變,

    Tip:在開發中我們應該盡量使用 int 作為列舉的基礎型別,除非因性能問題或互操作方面的考慮時才會考慮使用較小的型別,

一、列舉轉換

列舉轉換主要涉及到了列舉與列舉的轉換、列舉與數字和字串的轉換,

  1. 列舉之間轉換
    首先我要說明的是在 C# 中不支持不同列舉陣列之間的直接轉換,所以如果想要實作不同列舉陣列之間的轉換我們可以利用 CLR 寬松的賦值兼容性這一特點來進行轉換,需要轉換的兩個列舉必須具有相同的基礎型別,同樣,我們通過一個例子來看一下具體實作方法,
    static void Main(string[] args)
     {
         CountryAllName[] can = (CountryAllName[])(Array)new Country[4];
     }
    enum Country
     {
         CN,
         UK,
         JP,
         USA
     }
     enum CountryAllName
     {
         China,
         UnitedKingdom,
         Japan,
         UnitedStates
     }
    
    在使用這種方法時有可能會出現意外的錯誤或結果,并且相關開發規范中并沒有說這種方式每次都起作用,因此我不建議這么使用,除非在一些極端場景中,
  2. 列舉和字串之間轉換
    列舉轉換為字串可以直接使用 ToString() 方法, 列舉值 ToString 后會直接輸出列舉值識別符號的字串形式,例如 Country.CN.ToString() 得到的結果是字串 CN ,當然,你也可以利用 Enum.GetNamesEnum.GetName 方法來獲取,下面我簡單來講解一下這兩個方法的使用,
    • GetNames
      GetNames 方法需要傳入一個列舉型別,回傳值是一個字串陣列,例如需要獲取到 Country 的第二個國家,那么就可以這么來寫 Enum.GetNames(typeof(Country))[1],回傳結果是 UK ,
    • GetName
      GetName 方法回傳的是一個字串,這個字串就是需要獲取的指定列舉值的字串形式,同樣我們獲取第二個國家,Enum.GetName(typeof(Country),1) ,回傳的值同樣是 UK ,
      字串轉換為列舉也很簡單,同樣用到了 Enum 基類的一個靜態方法 Parse ,例如我們將 JP 轉換為列舉 Country 的列舉值可以這么做 (Country)Enum.Parse(typeof(Country),"JP") ,這里有一點需要注意,TryParse 方法是在 .net 4.0 才出現的,因此如果要在 .net 4.0 以下版本中將字串轉換為列舉時,需要進行恰當的錯誤處理防止字串不存在與列舉型別中的列舉值中,

    Tip:字串向列舉轉換不可本地化,如果必須本地化,就必須是那些對上層用戶不可見的訊息,因此在實際開發中應該盡量避免列舉和字串之間的轉換,

  3. 列舉和數字之間轉換
    列舉轉換為數字我們可以使用強轉,例如 (int)Country.CN 回傳結果是 0 ,從數字轉換為列舉我們有兩種方法,一種是使用強轉,另一種是使用 Enum 的靜態方發 ToObject
    • 強轉
      強轉就比較簡單了,Country country = (Country)2
    • ToObject
      ToObject 方法需要傳入列舉型別和需要轉換的數字,例如 Country country = (Country)Enum.ToObject(typeof(Country),2)
  4. 注意
    字串轉換為列舉和數字轉換為列舉都必須先進行判斷所要轉換的值是否包含在列舉中,判斷的方法也很簡單只需要呼叫 Enum 的靜態方法 IsDefined 即可,例如我要將 0 和 HK 轉換為列舉,代碼如下:
    Type type = typeof(Country);
     if(Enum.IsDefined(type,0))
     {
         Enum.ToObject(type, 0);
     }
     if(Enum.IsDefined(type,"HK"))
     {
         Enum.Parse(typeof(Country), "HK");
     }
    
    上述代碼中只有 0 會成功轉換為列舉值 CN ,因為 0 所對應的列舉值是 CN ,而 HK 并沒有在列舉中,

三、標志與屬性

這一小節我們來講解一下標志與屬性,標志和屬性屬于在開發中用的比較少,并且大部分程式員了解的也不多,

  1. 標志
    在開發中有時我們希望能對列舉進行組合使用來表示復合值,那么這時我們就需要定義標志列舉了,標志列舉的名稱為復數形式,代表了一個標志的集合,一般我們會使用按位或運算子鏈接列舉值,使用 HasFlags 方法或者按位與運算子來判斷特定的位是否存在,比較經典的標志列舉是位于 System.IO 命名空間中的 FileAttributes 標志列舉,它列出了檔案的所有屬性,比如只讀、隱藏、所在磁盤等等,它所包含的所有列舉值皆可相互組合,例如一個檔案既是隱藏檔案又是只讀檔案,定義標志列舉的方法如下:
    [Flags]
    enum WeekDays
     {
         Monday = 1,
         Tuesday = 2,
         Wednesday = 4,
         Thursday = 8,
         Friday = 16,
         Saturday = 32,
         Sunday = 64
     }
    
    在上面的代碼中你會發現一個規律,每個列舉值對應的整數值都是 2的n次方,這是為什么呢,在標志列舉中要求多個列舉值相互組合后的結果不能包含在標志列舉中,并且基于按位運算的特性可以很方便的使用位運算子來計算一個列舉值是否包含了另外一個列舉值,這在權限系統中相當有用,
  2. 屬性
    列舉值上同樣也可以使用屬性,例如我們需要列印輸出列舉值的中文名,我們就可以通過屬性的形式進行設定,首先我們需要定義一個屬性:
    public class EnumChineseAttribute : Attribute
     {
         private string m_strDescription;
         public EnumChineseAttribute(string chineseName)
         {
             m_strDescription = chineseName;
         }
    
         public string Description
         {
             get { return m_strDescription; }
         }
     }
     enum Country
     {
         [EnumChinese("中國")]
         CN,
         [EnumChinese("英國")]
         UK,
         [EnumChinese("日本")]
         JP,
         [EnumChinese("美國")]
         USA
     }
     static void Main(string[] args)
     {
         Country country = Country.CN;
         FieldInfo fieldInfo = country.GetType().GetField("CN");
         object[] attribArray = fieldInfo.GetCustomAttributes(false);
         EnumChineseAttribute attrib = (EnumChineseAttribute)attribArray[0];
         Console.WriteLine(attrib.Description);
         Console.Read();
     }
    
    通過上面的代碼我們就能獲取到 CN 對應的中文名稱了,這段代碼并沒有進行進一步優化,在實際專案中必須進行封裝和優化,

四、小結

這篇文章主要講解了列舉相關的知識,內容有點瑣碎,但是在實際開發中還是比較實用的,文章中我所提到的要點和規定在實際開發中已經經過驗證,各位讀者可以直接拿來使用,

本文由博客一文多發平臺 OpenWrite 發布!

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/73206.html

標籤:C#

上一篇:C#撰寫一個較完整的記事本程式

下一篇:正則運算式過濾html注釋內容

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more