位运算 - 检查和删除
Bitwise operations - checking and removal
注意下面的简单示例:
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.Test3
和 test = test And Not Names.Test3
但是,第一个会在缺少标志时添加标志,如果存在则将其删除,而第二个只会删除它。这是唯一的区别吗?还是我更喜欢一种方法而不是另一种方法的另一个原因?
你说你可以有效地替换这个是正确的:
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
请记住,Flags
枚举不一定都是纯粹的单位值。例如。想象一下(用更好的名字)你的枚举是:
<Flags>
Public Enum Names
None = 0
Test = 1
Test2 = 2
Test3 = 4
Test4 = 8
Test2AndTest4 = 10
End Enum
现在,您不想只测试 test And Names.Test2AndTest4
是否为非零,因为这不能回答正确的问题。因此,一般来说,养成 And
您的掩码进行检查然后与掩码值进行比较是一个更好的习惯,以确保掩码的 所有 位都已设置.
注意下面的简单示例:
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.Test3
和 test = test And Not Names.Test3
但是,第一个会在缺少标志时添加标志,如果存在则将其删除,而第二个只会删除它。这是唯一的区别吗?还是我更喜欢一种方法而不是另一种方法的另一个原因?
你说你可以有效地替换这个是正确的:
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
请记住,Flags
枚举不一定都是纯粹的单位值。例如。想象一下(用更好的名字)你的枚举是:
<Flags>
Public Enum Names
None = 0
Test = 1
Test2 = 2
Test3 = 4
Test4 = 8
Test2AndTest4 = 10
End Enum
现在,您不想只测试 test And Names.Test2AndTest4
是否为非零,因为这不能回答正确的问题。因此,一般来说,养成 And
您的掩码进行检查然后与掩码值进行比较是一个更好的习惯,以确保掩码的 所有 位都已设置.