我們常見到的位域標誌定義都是基於正數的,不過其實也可以定義成基於負數的,工作起來則和正數標誌位域一樣。
比如定義一個8位的位域,提供兩個選項分別是最高位和最低位為1。然後分別以byte和sbyte作為枚舉背後資料類型,則枚舉應該這樣聲明:
[Flags]
enum a : byte
{
//128的原碼為:10000000
High = 128,
Low = 1
}
[Flags]
enum b : sbyte
{
//-128的補碼為:10000000
High = -128,
Low = 1
}
接下來根據相應的類型,把變數的全部標誌都設定為1,然後判斷最高位和最低位是否被開啟。
//將全部標誌設定為1(開啟狀態)
//255原碼:1111 1111
var aFull = (a)255;
//-1補碼:1111 1111
var bFull = (b)(-1);
//通過枚舉僅將最高位和最低位開啟
var aMask = a.High | a.Low;
var bMask = (b.High | b.Low);
//判斷標誌是否被開啟
Console.WriteLine((aFull & aMask) == aMask);
Console.WriteLine((bFull & bMask) == bMask);
結果都會輸出True。
事實上,完全可以把它們轉換成同一個類型進行同樣的位操作,比如都轉換成byte類型:
static void Main(string[] args)
{
//將全部標誌設定為1(開啟狀態)
//255原碼:1111 1111
var aFull = (a)255;
//-1補碼:1111 1111
var bFull = (b)(-1);
doo((byte)aFull);
doo((byte)bFull);
}
static void doo(byte b)
{
//129原碼:1000 0001
byte mask = 129;
Console.WriteLine((b & mask) == mask);
}
上面代碼同樣會輸出兩個True。原因是當一個負數被強制轉換成無符號數字,它背後的位元據會被強行塞進對應變數空間,所以從位域的角度看,沒有發生任何變化。(更多關於C#強制轉換的越界檢查可以參考這篇文章:http://www.cnblogs.com/mgen/archive/2012/04/08/2438029.html)
.NET 4.0新加的Enum.HasFlag方法的工作原理就是這樣的,只不過它用的是無符號Long(ulong),如:
因此我們也可以寫一個簡單的枚舉位操作輔助類型,如下:
static class EnumHelper
{
//判讀是否包含指定標誌位
public static bool HasFlag(long val, long flag)
{
return (val & flag) == flag;
}
//設定標誌位
public static long SetFlag(long val, long flag)
{
return val | flag;
}
//取消標誌位
public static long UnsetFlag(long val, long flag)
{
return val & ~flag;
}
}