在狀態表達的設計手法中,有一種是以 2 的 n 次方來設計,例如:Status1 = 1、Status2 = 2、Status3 = 4、...依此類推,當我們得知某物件的 Status = 5,我們就知道它包含了 Status1 以及 Status3(因為 5 = 1 + 4),.NET Framework 中有一個列舉型別 System.Reflection.BindingFlags 就是這樣設計的,那重點來了,我們要怎麼知道任意一個正整數可以由哪些 2 的次方加總結果呢?
想不到我們又再度地與 >>(右移)和 <<(左移)運算子見面了(請參考此篇文章),除此之外這次還會使用到 yield 關鍵字,我們限定數值型別為 int 跑一個迴圈,索引值從 1 開始,每迴圈一次就 <<= 1
,將目標參數 value 與當前的索引值做 & 運算,若結果 > 0 則 yield return 當前的索引值,並且從 value 中減掉當前的索引值,直到 value == 0 時 yield break,這樣我們就可以知道目標參數 value 是由哪些 2 的次方加總得來的了。
private static IEnumerable<int> GetBinaryExponentiations(int value)
{
for (var currentPow = 1; currentPow != 0; currentPow <<= 1)
{
if ((currentPow & value) > 0)
{
yield return currentPow;
if ((value -= currentPow) == 0) yield break;
}
}
}
執行結果: