С# Производительность и лучшие практики для проверки состояния битового массива

Вот моя проблема:

  • У меня есть два класса: ClassObj и ClassProperty;
  • Одно из свойств ClassObj (назовем его lstProperty) является List из ClassProperty (представляющим свойство, которым обладает текущий экземпляр объекта);
  • Во время выполнения я где-то сохранил Array из всех возможных ClassProperty, мы будем называть это Array arrPossibleProperty.

Моя проблема состоит в том, чтобы найти ДЕЙСТВИТЕЛЬНО быстрый способ проверить, соответствует ли экземпляр ClassObj определенному набору ClassProperty (если у него есть в его lstProperty все ClassProperty данного набора).

Я думал о создании array из Bit, представляющих последовательность ClassProperty, которыми владеет ClassObj. Используя в качестве ссылки Array arrPossibleProperty и индекс его Property.

Итак, если, например, у нас есть свойство 10, а InstanceA из ClassObj имеют 1-е, 4-е и 9-е, я бы сгенерировал этот битовый массив: 1001000010

У меня вопрос: как я могу проверить, например (самое быстрое и эффективное решение), что массив битов имеет (например) 3-е и 4-е свойства?

Конечно, если вам нужен более эффективный способ сделать это, дайте мне знать.


person SeraphimFoA    schedule 06.02.2013    source источник


Ответы (2)


Вы захотите использовать побитовые операции, такие как &, |, ^ или ~ (в зависимости от ваших потребностей)

Взяв ваш пример 1001000010, чтобы узнать, установлен ли 3-й бит, вы должны сделать это: 1001000010 & 0000000100 != 0000000000 или, скорее,

bool isSet = myProperty & (1 << (option - 1)) != 0; // to find out if `myProperty` has the property `option` set.
myProperty |= 1 << (option -  1); // to set property `option`

Дополнительные сведения о побитовых операциях: http://en.wikipedia.org/wiki/Bitwise_operation.

В качестве альтернативы и гораздо более простой в реализации можно было бы использовать перечисления.

[Flags]
enum ClassProperty
{
    None = 0x00,
    First = 0x01,
    Second = 0x02,
    Third = 0x04,
    Fourth = 0x08
    // add more if needed
}

Затем вы должны использовать перечисление следующим образом

myProperty = ClassProperty.First | ClassProperty.Second; // sets both First and Second
bool thirdIsSet = myProperty.HasFlag(ClassProperty.Third);
person Nolonar    schedule 06.02.2013
comment
Спасибо за ответ. Я попробую обе реализации, чтобы увидеть, какая из них будет наиболее производительной. Спасибо большое! - person SeraphimFoA; 06.02.2013
comment
Обратите внимание, что вы можете одновременно проверять несколько флагов, например. myProperty.HasFlag(ClassProperty.Third | ClassProperty.Fourth). Однако использование HasFlag, вероятно, будет в тысячи раз медленнее, чем использование битовых флагов. (Хотя мы сравниваем миллисекунды с наносекундами;) - person Matthew Watson; 06.02.2013

Вы говорите, что ваш массив всех возможных объектов ClassProperty (arrPossibleProperty) инициализируется во время выполнения. Затем я предполагаю, что вы не знаете, насколько большим может быть этот массив. Это исключает перечисления, которые по определению жестко запрограммированы. Если вместо этого вы выберете какое-то растровое изображение, как вы указали в своем вопросе, вам нужно в какой-то момент выполнить итерацию arrPossibleProperty и вашего списка ClassProperty lstProperty, чтобы выполнить сопоставление и удаление.

Я хочу сказать, что вы делаете много предположений, утверждая, что выполнение этой битовой игры быстрее, в то время как вы фактически работаете с высокоуровневыми объектами С#. Никогда не предполагайте. Контрольная работа. Мера.

Вот вопрос, очень похожий на ваш , в котором ответ использует стандартные функции библиотеки .NET, чтобы делать то, что вы хотите:

HashSet<T>().IsSupertSetOf().

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

person Nilzor    schedule 06.02.2013