枚举类型位标致[Flags]特性的使用以及为枚举类型添加方法
假设有段代码是这样的,需要判断角色装备哪些武器,然后根据角色的这个属性来进行其它的一些操作。这时候我们可以用枚举来标记角色可以装备的武器。
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 }