Note the simple example below:
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
The first part of my question relates to the line If (test And Names.Test3) = Names.Test3
.
Wouldn't it be better to simply check If test And Names.Test3
as if the flag exists? If it evaluates to a non-zero value (meaning the flag exists) then the result of the condition would be True
anyway.
Is there a good reason to use the first way of checking over the second? (Whilst my answer is for VB.NET, I would also be interested in knowing if this is a potential pitfall anywhere else, ie C#, C++, etc).
Also, with regards to flag removal, it seems there's two ways to do this:
test = test Xor Names.Test3
and test = test And Not Names.Test3
However, the first will add the flag if it's missing, and remove it if it is there, whereas the second will only remove it. Is that the only difference? Or is there another reason why I should prefer one method over the other?
You are correct in stating that you can effectively replace this:
If (test And Names.Test3) = Names.Test3 Then
with this
If (test And Names.Test3) Then
But, the second example will not compile with Option Strict On
as you rightly get the error:
Option Strict On disallows implicit conversions from 'Names' to 'Boolean'
so in order to get this to compile you need to wrap a CBool
round it.
So, in conclusion I would say it is much better to use the first example as the intent is very clear:- you are checking to see if a bit is set.
In terms of flag removal i.e. unsetting a bit you should use:
test = test And Not Names.Test3
Using Xor
has the effect of toggling the value.
The following might help (especially if you make them extension methods):
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
Remember that Flags
enums don't have to all be purely single bit values. E.g. imagine (with better names) that your enum was :
<Flags>
Public Enum Names
None = 0
Test = 1
Test2 = 2
Test3 = 4
Test4 = 8
Test2AndTest4 = 10
End Enum
Now, you wouldn't want to just test that test And Names.Test2AndTest4
is non-zero since that doesn't answer the correct question. So it's a better habit to get into, in general, to And
your mask to check and then compare to the mask value, to ensure that all bits of the mask are set.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With