列舉介紹,以及列舉成員的組合,判斷,移除
列舉
列舉可用於限定選擇範圍,他包含了一系列基於整數型別(某些語言會提供更多的型別選擇)的列舉成員,當你指定函式的參數為某種列舉時,引數就需要是該列舉的某個成員。列舉的常見用途可能是,表示可選擇的色彩,表示當周日次,表示一年中的月份。
列舉是實值型別的,雖然在某些語言的程式碼中,他表現為類別,但一些約束將使其具有確定的儲存空間,以符合實值型別的要求。
為何使用列舉?
相對於直接使用數值,列舉具有更好的可讀性,成員名稱可以表達某種含義。相對於使用常數或字串,列舉更容易維護,在 IDE 的幫助下,修改會更為簡單,不容易產生錯誤。
列舉成員
每一個列舉成員都應該對應一個整數型別的值,這不意味著需要逐個為他們指定,在預設情況下,語言會自動為列舉成員分配一個值,其一般規則為,第一個成員對應0
,之後的成員依次遞增1
。
當然,如果有必要,你可以為某個或多個列舉成員指定自己希望的值,而其余成員依然會依據某種規則,獲得自動分配的值。
下面的 C# 列舉Color
,成員Black
和Blue
被指定了值,成員Red
和Yellow
根據上一個成員遞增了1
。
// 列舉 Color,表示色彩
public enum Color {
// 未設定,0
None,
// 白色,1
White,
// 黑色,10
Black = 10,
// 紅色,11
Red,
// 藍色,100
Blue = 100,
// 黃色,101
Yellow,
}
組合列舉成員
在實際的專案開發中,我們可能會遇到需要組合多個列舉成員的情況,比如,對於表示當周日次的列舉,只選擇某一天是沒有問題的,但如何表示其中兩天的組合哪?要完成此目標,可執行如下兩個步驟。
首先,需要組合的列舉成員對應的整數應該是0
或2ⁿ
,其中n
從0
開始並依次遞增,這樣的設計可以確保無論組合是怎樣的,組合的結果都有合適的“位置”,不與任何成員重複。
然後,對想要組合的列舉成員,使用或位元運算子(|
)即可。其中,任何其他支援組合的列舉成員與0
(值等於0
的成員)組合將等於這些列舉成員自身。
在下面的 C# 程式碼中,我們使用運算子|
組合了列舉DayOfWeek
的兩個成員Monday
和Tuesday
,變數days
顯示的輸出為3
,不與DayOfWeek
中的任何成員重複。將值為0
的成員None
與days
組合,組合結果與days
相等。
// 組合成員 Monday 和 Tuesday
DayOfWeek days = DayOfWeek.Monday | DayOfWeek.Tuesday;
Console.WriteLine($"days={days}");
// 與 None 組合
Console.WriteLine($"與 None 組合後等於自身?{days == (days | DayOfWeek.None)}");
days=3
與 None 組合後等於自身?True
// 列舉 DayOfWeek,表示當周日次
public enum DayOfWeek
{
// 未設定
None = 0,
// 周一
Monday = 1,
// 周二
Tuesday = 2,
// 周三
Wednesday = 4,
// 周四
Thursday = 8,
// 周五
Friday = 16,
// 周六
Saturday = 32,
// 周日
Sunday = 64,
}
判斷列舉成員是否包含在列舉成員組合中
在成功實作了多個成員的組合後,如何判斷列舉成員是否包含在組合中哪?這個問題較為簡單,對成員組合和需要判斷的成員,使用與位元運算子(&
),並將結果和需要判斷的成員比較即可。如果與位元運算子(&
)的運算元都是成員組合,那麽將判斷一個組合中的成員是否同時出現在了另一個組合中。
值為0
的列舉成員,將被認為包含在任何支援組合的列舉成員,或他們的任意組合中。
下面的 C# 函式Rest
,將判斷參數dayOfWeek
是否包含了列舉DayOfWeek
的成員Saturday
或Sunday
。值為0
的成員None
包含在成員Monday
與Tuesday
的組合中。
// 函式 Rest 將根據是否是周末來顯示資訊
void Rest(DayOfWeek dayOfWeek)
{
DayOfWeek weekend = DayOfWeek.Saturday | DayOfWeek.Sunday;
if ((weekend & dayOfWeek) == weekend)
Console.WriteLine("休息兩天!");
else if ((DayOfWeek.Saturday & dayOfWeek) == DayOfWeek.Saturday || (DayOfWeek.Sunday & dayOfWeek) == DayOfWeek.Sunday)
Console.WriteLine("周末的味道!");
else
Console.WriteLine("枯燥的味道!");
}
// 傳遞周一,周五,周六的組合
Rest(DayOfWeek.Monday | DayOfWeek.Friday | DayOfWeek.Saturday);
// 傳遞周二,周三
Rest(DayOfWeek.Tuesday | DayOfWeek.Wednesday);
// 傳遞周四,周六,周日的組合
Rest(DayOfWeek.Thursday | DayOfWeek.Saturday | DayOfWeek.Sunday);
// 周一和周二的組合包含了 None
Console.WriteLine($"days 包含 None?{(days & DayOfWeek.None) == DayOfWeek.None}");
周末的味道!
枯燥的味道!
休息兩天!
days 包含 None?True
移除列舉成員組合中的列舉成員
通過互斥或位元運算子(^
),你可以將一個或多個列舉成員從成員組合中移除。當然,互斥或位元運算子(^
)還帶有或位元運算子(|
)的效果,列舉成員會被新增,先決條件是他們未在組合中出現。
任何其他支援組合的列舉成員移除0
(值等於0
的成員)後依然等於這些列舉成員自身。
在下面的程式碼中,周二Tuesday
將被互斥或位元運算子(^
)移除,運算的結果為周一Monday
和周三Wednesday
的組合。
DayOfWeek day12 = DayOfWeek.Monday | DayOfWeek.Tuesday;
DayOfWeek day23 = DayOfWeek.Tuesday | DayOfWeek.Wednesday;
// 周二將被移除,周一和周三將被組合
DayOfWeek day13 = day12 ^ day23;
Console.WriteLine($"包含周一?{(day13 & DayOfWeek.Monday) == DayOfWeek.Monday}");
Console.WriteLine($"包含周二?{(day13 & DayOfWeek.Tuesday) == DayOfWeek.Tuesday}");
Console.WriteLine($"包含周三?{(day13 & DayOfWeek.Wednesday) == DayOfWeek.Wednesday}");
// 移除 None
Console.WriteLine($"移除 None 之後等於自身?{(day13 ^ DayOfWeek.None) == day13}");
包含周一?True
包含周二?False
包含周三?True
移除 None 之後等於自身?True
取得相反的列舉成員
對於列舉成員(包括值為0
的成員)或列舉成員的組合,使用反相位元運算子(~
)可以取得列舉中這些成員之外的所有列舉成員。
列舉成員或列舉成員組合的反相運算結果可能包含未定義的列舉成員
在一些程式設計語言中,對列舉成員或列舉成員組合執行反相操作,意味著取得這些成員之外的所有組合狀況,這不僅涉及列舉中已經定義的列舉成員,還包括任何未定義的成員,因此反相的運算結果與剩余已定義列舉成員的組合併不相同。
在下面的程式碼中,我們通過反相位元運算子~
,取得了周末以外的列舉成員(包括未定義的成員)的組合,他與成員周一到周五的組合併不相同。
// workdays 是工作日的組合
DayOfWeek workdays = ~(DayOfWeek.Saturday | DayOfWeek.Sunday);
Console.WriteLine($"周一是工作日?{(workdays & DayOfWeek.Monday) == DayOfWeek.Monday}");
Console.WriteLine($"周五是工作日?{(workdays & DayOfWeek.Friday) == DayOfWeek.Friday}");
Console.WriteLine($"相等?{workdays == (DayOfWeek.Monday | DayOfWeek.Tuesday | DayOfWeek.Wednesday | DayOfWeek.Thursday | DayOfWeek.Friday)}");
周一是工作日?True
周五是工作日?True
相等?False