枚舉有個特性叫標誌位,使用方法如下
[Flags] enum Foo { a =1, b = 2, c = 4, d = 8 }
每個值需要爲2的n次方,保證多個值的組合不會重複.
這樣在判斷其中一個枚舉值c 是否在a,b,c這個範圍中就可以簡化寫法
常規寫法如下
var c = Foo.c; if( c == Foo.a || c == Foo.b || c == Foo.c ) { }
因爲值爲2的n次方,所以可以通過按位相與來得出是否在範圍內
var c = Foo.c; if( (c & ( Foo.a | Foo.b | Foo.c ) != c ) { }
注意,如果c在範圍內則結果等於c,否則結果爲0
可以寫個擴展方法
public static class EnumExtension { /// <summary> /// 判斷該枚舉是否在範圍內 注意:該枚舉類型需要有[Flags] 標註 /// </summary> /// <param name="source">待比較的值</param> /// <param name="range">枚舉範圍</param> /// <returns></returns> public static bool IsIn(this Enum source, params Enum[] range) { if(range.Length == 0) { return false; } else if(range.Length == 1) { return source == range[0]; } int r = Convert.ToInt32(range[0]); for (int i = 1; i < range.Length; i++) { r |= Convert.ToInt32(range[i]); } return !((Convert.ToInt32(source) & r) == 0); } }
調用如下
var c = Foo.c; if(c.IsIn(Foo.a, Foo.b, Foo.c)) { }
此外flags還會重寫該枚舉的ToString()
比如 由於3 = 1 | 2,所以3就相當於a|b
當對3強轉爲Foo後進行ToString會輸出 a,b 而不是3
這樣簡單組合就可以得到新的有效枚舉值,這種設計在權限等方面應用很多.
比如linux的文件權限 read write execute,縮寫爲r w x,對應值爲 4 2 1
當需要一個值爲
可讀可寫, r w, 4 | 2 = 6
可寫可執行, w x, 2 | 1 = 3
可讀可執行, r x, 4 | 1 = 5
可讀可寫可執行 r w x, 4 | 2 | 1 = 7
當然,也可以加上命名指定枚舉值組合,比如定義一個ac 來替代a|c
[Flags] enum Foo { a = 1, b = 2, c = 4, ac = a | c, d = 8 }