FlagsAttribute特性的使用还是很常见的,他只能应用于Enum枚举数,下面是官方文档的说明
(官方文档:https://docs.microsoft.com/en-us/dotnet/api/system.flagsattribute?view=netframework-4.7.2)
Indicates that an enumeration can be treated as a bit field; that is, a set of flags.
用于表明一个枚举可以当作位标志来处理.即一组标志。简单说:当我们在使用枚举的值与值之间进行组合的时候(按位OR),Flags属性可以给我们提供更直观的格式化输出(以字符串的形式输出每个枚举值)方便我们调试,即改变了System.Enum的ToString和Format的行为。
枚举Enumerationk中定义的值通常是互斥的,比如方向,颜色,我们在只涉及到一种值的情况下,不需要考虑,但有些需求是会出现值与值之间存在可能的组合关系(combination),而且这种需求会在开发中非常的实用。
比如前面讲过的反射(Reflection),我在通过字符串搜索成员的时候,需要指定BindingFlags(枚举),我可能要同时包含Instance,Public,NoPublic,DeclaredOnly等等多个条件,这时候使用位操作是最简单的方法。而使用FlagsAttribute可以给我们带来更多的便利性(当然实现位操作他不是必要的)
实现元素的组合,要对枚举(Ennumeration)的值有要求,必须是2的N次幂,如1,2,4,8.....
这样定义,每一个值都占有一个独立的位,相当于开关,不会重叠,如下图:
通过位|(OR)操作符,将需要的位打开,如:
public enum Vegetables
{
Cabbage = 1<<0,
Carrot = 1<<1,
Cuke = 1<<2,
Potato = 1<<3,
}
......
Vegetables vegetables = Vegetables.Cabbage | Vegetables.Carrot | Vegetables.Cuke | Vegetables.Potato;
//vegetables里同时包含了4种蔬菜,结果是:15,如图所示:
这时候在控制台输出vegetables的值,打印出来15,因为15这个值在枚举中并没有定义过,但通常这种输出的值并不利于我们调试,我们无法马上知道15或是其它值是由哪些值组合而来的,我们希望能够更直观的看到他们,在这里使用FlagsAttribute可以对位标志的值提供更好的格式化输出,以字符串的形式呈现。
如我们将枚举修改如下:
[Flags]//添加Flags属性
public enum Vegetables
{
Cabbage = 1<<0,
Carrot = 1<<1,
Cuke = 1<<2,
Potato = 1<<3,
}
这时候再输出vetegables的值,控制台会输出如下:
Cabbage, Carrot, Cuke, Potato
这样的结果才方便我们去调试.
在将这些值组合起来之后,我如何验证我是否包含了哪个值?即是否打开了哪个开关?
通过位&(AND)操作符
bool containCarrot = (vegetables&Vegetables.Carrot) == Vegetables.Carrot;
如图:
二进制1111和0010进行位&运算,结果是0010,Carrot位是打开的
如何关闭已经打开的位标志?
实际上就是将该位设置为0.比如我要关闭(删除)Carrot这个值
代码如下:
vegetables &= (~Vegetables.Carrot);
1111&=(~0010)=1111&=1101
结果为:13(Cabbage, Cuke, Potato)
(这里就不再上图了)
位标志的用途非常多,多条件的需求,除了上面说到的反射(多条件查询BindingFlags),比如主角的被动技能,加速,回血,无敌,防御力,xx力提升等等,可以同时作用于角色,通过位标志的组合可以很方便的实现该功能.
到此为止,如果大家发现有什么不对的地方,欢迎指正,共同提高,感谢您的阅读!
编辑于2018.7.12
--闲言碎语
(最近知了猴又出来了,每年都要拿着手电筒去树上找,这是小时候最快乐的趣事儿之一,那时候会抓回来炸着吃,飞来飞去的就用蜘蛛网或塑料袋做成的捕捉工具来抓,然后烤着吃,味道非常香...)