2016-07-05 13 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.Test3 и test = test And Not Names.Test3

Тем не менее, первый добавит флаг, если он отсутствует, и удалить его, если он там, тогда как второй удалит его только. Разве это единственная разница? Или есть еще одна причина, почему я должен предпочесть один метод другому?

+0

Мы обычно только как 1 вопрос. Но для вашего второго, это разница для вашего дела. Это становится более сложным, когда вы начинаете комбинировать флаги (test 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 efault-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 Or Names.Test4'? – Interminable

+1

@Interminable - когда определенная комбинация опций будет исключительно распространена, тогда обычно бывает, что она имеет более удобное имя, а не всегда вызывает побитовые операции в точке использования. Например. в различных 'File *' перечислениях в 'System.IO', большинство из них имеют определенный член' ReadWrite'. –

+0

После некоторого чтения, похоже, что это скорее исключение, чем правило. Если бы у меня была определенная комбинация флагов, которая, безусловно, многократно использовалась бы, я мог бы подумать об этом, но сейчас «ReadWrite» - единственный пример, который я смог найти. – Interminable

 Смежные вопросы

  • Нет связанных вопросов^_^