2016-07-05 27 views
3

注意以下簡單的例子:位運算 - 檢查和清除

Module Module1 
    <Flags> 
    Public Enum Names 
     None = 0 
     Test = 1 
     Test2 = 2 
     Test3 = 4 
     Test4 = 8 
    End Enum 

    Sub Main() 
     Dim test As Names = Names.Test Or Names.Test3 
     If (test And Names.Test3) = Names.Test3 
      Console.WriteLine("TRUE") 
     Else 
      Console.WriteLine("FALSE") 
     End If 
    End Sub 
End Module 

我的問題的第一部分涉及行If (test And Names.Test3) = Names.Test3

簡單地檢查If test And Names.Test3好像標誌存在不是更好嗎?如果它評估爲一個非零值(意味着該標誌存在),則該條件的結果總是爲True

是否有充分的理由使用第二種檢查方式? (雖然我的答案是針對VB.NET,但我也有興趣知道這是否是其他地方的潛在缺陷,即C#,C++等)。

此外,關於標誌去除,似乎有兩種方法可以做到這一點:

test = test Xor Names.Test3test = test And Not Names.Test3

然而,首先會增加,如果缺少它的標誌,並刪除它,如果它是那裏,而第二個只會刪除它。這是唯一的區別嗎?或者還有另一個原因,爲什麼我應該更喜歡一種方法而不是另一種?

+0

我們平時只有像1個問題。但對於你的第二,這是你的情況的差異。當你開始合併標誌(測試Xor(Names.Test2或Names.Test3))時,它會變得更加複雜。在這種情況下,如果你沒有打開兩個標誌,Xor可能會產生奇怪的結果。 –

+0

我想我的問題已經足夠小了他們不應該被拆分,你所標記的Xor'似乎能夠按照我的預期工作,它只是一次完成所有的事情,在你的例子中,它增加了'Names.Test2',因爲它不存在,並刪除'Names.Test3',因爲它(已經存在)! – Interminable

回答

2

你在陳述是正確的,你可以有效地替換此:

If (test And Names.Test3) = Names.Test3 Then

與此

If (test And Names.Test3) Then

,第二個例子不會Option Strict On編譯你正確地得到錯誤:

Option Strict On disallows implicit conversions from 'Names' to 'Boolean'所以爲了得到這個編譯你需要包裝一個CBool圍繞它。

因此,總而言之,我認爲使用第一個例子會更好,因爲意圖非常明確: - 您正在檢查是否設置了一位。

在標誌去除即解封一點來講,你應該使用:

test = test And Not Names.Test3

使用Xor切換值的影響。

下可能會幫助(尤其是如果你把它們擴展方法):

Public Function SetBit(ByVal aValue As Names, ByVal aBit As Names) As Names 
    Return (aValue Or aBit) 
End Function 

Public Function ClearBit(ByVal aValue As Names, ByVal aBit As Names) As Names 
    Return (aValue And Not aBit) 
End Function 

Public Function IsBitSet(ByVal aValue As Names, ByVal aBit As Names) As Boolean 
    Return ((aValue And aBit) = aBit) 
End Function 

Public Function ToggleBit(ByVal aValue As Names, ByVal aBit As Names) As Names 
    Return (aValue Xor aBit) 
End Function 
+0

Argh!我通常將Option Strict和Option Explicit都設置爲On,但我只是將它創建爲一個簡單的測試項目,獲得對按位操作的理解......並忘記了!感謝您指出這一點絕對是第一種方法的一個很好的理由您對我的問題的第二部分有關標誌移除的想法嗎 – Interminable

+2

您可以*默認*嚴格在:http://stackoverflow.com/questions/5160669/option-strict-on-by-d vfault-in-vb-net - 這應該是開箱即用的設置。爲MS改變這個投票:https://visualstudio.uservoice.com/forums/121579-visual-studio-2015/suggestions/10672947-set-option-strict-on-by-default-instead-of-off –

+1

我知道在項目設置中將它設置爲整個項目,我不知道我可以讓Visual Studio在默認情況下執行此操作!非常便利。你鏈接的想法有我的投票。 – Interminable

2

記住Flags枚舉不必全部是純粹的單位值。例如。想象(更好的名字),你的枚舉是:現在

<Flags> 
Public Enum Names 
    None = 0 
    Test = 1 
    Test2 = 2 
    Test3 = 4 
    Test4 = 8 
    Test2AndTest4 = 10 
End Enum 

,你不會只想測試test And Names.Test2AndTest4非零因爲這並沒有回答正確的問題。所以這是一個更好的習慣,一般來說,要將你的掩碼And檢查一下,然後與掩碼值進行比較,以確保掩碼的所有位都被設置。

+0

這是明智的嗎?我無法想象這些單詞來描述我對此的感受,但是將相同的'Enum'中創建新的'Enum'條目組合起來以結合現有的'Enum'條目感覺有點偏離。另外,即使我這樣做,而不是'Test2AndTest4 = 10',我不應該只是'Test2AndTest4 = Names.Test2或Names.Test4'? – Interminable

+1

@Interminable - 當特定的選項組合將非常常見時,通常會給它一個更方便的名稱,而不是總是在使用位置強制按位操作。例如。在'System.IO'的各種'File *'枚舉中,它們中的大多數都有一個特定的'ReadWrite'成員。 –

+0

經過一番閱讀,看起來這種事情可能是例外而非規則。如果我有一個特定的標誌組合,肯定會被重複使用,但是我現在可能會考慮它,現在'ReadWrite'是我能找到的唯一例子。 – Interminable