假設有段代碼是這樣的,需要判斷角色裝備哪些武器,然後根據角色的這個屬性來進行其它的一些操作。這時候我們可以用枚舉來標記角色可以裝備的武器。 這就有個問題了,當角色可以裝備多種武器的時候,難道要用多個變數去表示他可以使用的武器嗎?又或者是在Equipment類型中加入新的成員,刀和箭,刀和箭和弓... ...
假設有段代碼是這樣的,需要判斷角色裝備哪些武器,然後根據角色的這個屬性來進行其它的一些操作。這時候我們可以用枚舉來標記角色可以裝備的武器。
public enum Equipment { 刀, 槍, 箭, 弓 } public sealed class Player { internal Equipment equipmentState;//用於描述角色可以使用哪些武器 //......其它成員 }
這就有個問題了,當角色可以裝備多種武器的時候,難道要用多個變數去表示他可以使用的武器嗎?又或者是在Equipment類型中加入新的成員,刀和箭,刀和箭和弓...... 造成這種原因的是Player中的equipmentState只能表示一種狀態,不能表示多種狀態。
即它的值只能是刀,槍,箭,弓中的一個。
這時候可以用Flags特性為修飾Equipment類型。它可以讓equipmentState有能力可以表示成多種狀態,現在equipmentState就相當於集合一樣。
1 namespace UsageOfFlagsAttribute 2 { 3 [Flags] 4 public enum Equipment 5 { 6 NONE = 0x0000, 7 刀 = 0x0001, 8 槍 = 0x0002, 9 箭 = 0x0004, 10 弓 = 0x0008 11 } 12 13 public sealed class Player 14 { 15 internal Equipment equipmentState;//用於描述角色可以使用哪些武器 16 } 17 18 19 class Program 20 { 21 static void Main(string[] args) 22 { 23 Player player = new Player(); 24 player.equipmentState = Equipment.刀 | Equipment.弓; //可以表示成多種狀態的集合 25 } 26 } 27 }
用Flags標記後也就可以按位計算了,一般枚舉有3種按位計算。
按位或(“|”):將指定的符號加入到枚舉實例中
按位與(”&“):判斷枚舉實例中是否有指定的符號
異或(”^“):刪除枚舉實例中指定的符號
class Program { static void Main(string[] args) { Player player = new Player(); //按位或 player.equipmentState = Equipment.刀; player.equipmentState = player.equipmentState | Equipment.弓; Console.WriteLine(player.equipmentState.ToString());//列印結果:刀,弓 //按位與 player.equipmentState = Equipment.刀 | Equipment.弓; player.equipmentState = player.equipmentState & Equipment.刀; Console.WriteLine(player.equipmentState.ToString()); //列印結果 : 刀 //異或 player.equipmentState = Equipment.刀 | Equipment.弓; player.equipmentState = player.equipmentState ^ Equipment.弓; Console.WriteLine(player.equipmentState.ToString()); //列印結果 : 刀 Console.ReadKey(); } }
但是每次都要寫 player.equipmentState = player.equipmentState ^ Equipment.弓; 這麼賦值代碼的可讀性不好,而且容易浪費時間。因此可以擴展方法來封裝這些操作。
1 public static class EnumExtendMethods 2 { 3 /// <summary> 4 /// 判斷位標緻的枚舉實例中是否有指定符號 5 /// </summary> 6 /// <param name="eqipment">實例</param> 7 /// <param name="checkState">指定的符號</param> 8 /// <returns></returns> 9 public static bool Contains(this Equipment equipment,Equipment checkState) 10 { 11 if (checkState == 0) 12 { 13 throw new ArgumentOutOfRangeException("checkState", "不能為NONE"); 14 } 15 return (equipment & checkState) == checkState; 16 } 17 18 /// <summary> 19 /// 將指定的符號從枚舉實例中移除 20 /// </summary> 21 /// <param name="equipment"></param> 22 /// <param name="removeState">指定要移除的符號</param> 23 /// <returns></returns> 24 public static Equipment Remove(this Equipment equipment, Equipment removeState) 25 { 26 return equipment ^ removeState; 27 } 28 29 /// <summary> 30 /// 向枚舉實例中加入指定的符號 31 /// </summary> 32 /// <param name="equipment"></param> 33 /// <param name="addState"></param> 34 /// <returns></returns> 35 public static Equipment Append(this Equipment equipment, Equipment addState) 36 { 37 return equipment | addState; 38 } 39 }
現在可以這樣調用了
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Player player = new Player(); 6 7 //按位或 8 player.equipmentState = Equipment.刀; 9 player.equipmentState = player.equipmentState.Append(Equipment.弓); 10 Console.WriteLine(player.equipmentState.ToString());//列印結果:刀,弓 11 12 //按位與 13 player.equipmentState = Equipment.刀 | Equipment.弓; 14 if (player.equipmentState.Contains(Equipment.刀)) 15 { 16 Console.WriteLine(player.equipmentState.ToString()); //列印結果 : 刀,弓 17 } 18 19 //異或 20 player.equipmentState = Equipment.刀 | Equipment.弓; 21 player.equipmentState = player.equipmentState.Remove(Equipment.弓); 22 Console.WriteLine(player.equipmentState.ToString()); //列印結果 : 刀 23 24 Console.ReadKey(); 25 } 26 }