Наиболее распространенные побитовые операции C # над перечислениями

c# .net enums bit-manipulation flags

154196 просмотра

10 ответа

4806 Репутация автора

На всю жизнь я не могу вспомнить, как устанавливать, удалять, переключать или тестировать немного в битовом поле. Либо я не уверен, либо я их перепутал, потому что они мне редко нужны. Так что было бы неплохо иметь "бит-лист".

Например:

flags = flags | FlagsEnum.Bit4;  // Set bit 4.

или же

if ((flags & FlagsEnum.Bit4)) == FlagsEnum.Bit4) // Is there a less verbose way?

Можете ли вы привести примеры всех других распространенных операций, предпочтительно в синтаксисе C # с использованием перечисления [Flags]?

Автор: steffenj Источник Размещён: 18.09.2008 03:46

Ответы (10)


0 плюса

20755 Репутация автора

C ++ операции: & | ^ ~ (для и, или, xor, а не побитовых операций). Также представляют интерес >> и <<, которые являются операциями битового сдвига.

Таким образом, чтобы проверить бит, установленный во флаге, вы должны использовать: if (flags & 8) // тестовый бит 4 установлен

Автор: workmad3 Размещён: 18.09.2008 03:50

86 плюса

3259 Репутация автора

Идиома состоит в том, чтобы использовать битовый или равный оператор для установки битов:

flags |= 0x04;

Чтобы немного прояснить, идиома должна использовать побитовое и с отрицанием:

flags &= ~0x04;

Иногда у вас есть смещение, которое идентифицирует ваш бит, и тогда идиома состоит в том, чтобы использовать их в сочетании со сдвигом влево:

flags |= 1 << offset;
flags &= ~(1 << offset);
Автор: Stephen Deken Размещён: 18.09.2008 03:50

7 плюса

69676 Репутация автора

Синтаксис C ++, предполагая, что бит 0 равен LSB, предполагая, что flags не имеет длинных знаков:

Проверьте, установлено ли:

flags & (1UL << (bit to test# - 1))

Проверьте, не установлено ли:

invert test !(flag & (...))

Задавать:

flag |= (1UL << (bit to set# - 1))

Очистить:

flag &= ~(1UL << (bit to clear# - 1))

Переключение:

flag ^= (1UL << (bit to set# - 1))
Автор: Petesh Размещён: 18.09.2008 03:57

3 плюса

53 Репутация автора

Чтобы проверить немного, вы должны сделать следующее: (при условии, что флаги - это 32-битное число)

Тестовый бит:

if((flags & 0x08) == 0x08)
(Если бит 4 установлен, то он имеет значение true) Переключить назад (1 - 0 или 0 - 1):
flags = flags ^ 0x08;
Сбросить бит 4 в ноль:
flags = flags & 0xFFFFFF7F;

Автор: Nashirak Размещён: 18.09.2008 04:00

284 плюса

20562 Репутация автора

Я проделал еще несколько работ над этими расширениями - вы можете найти код здесь

Я написал несколько методов расширения, которые расширяют System.Enum, которые я часто использую ... Я не утверждаю, что они пуленепробиваемые, но они помогли ... Комментарии удалены ...

namespace Enum.Extensions {

    public static class EnumerationExtensions {

        public static bool Has<T>(this System.Enum type, T value) {
            try {
                return (((int)(object)type & (int)(object)value) == (int)(object)value);
            } 
            catch {
                return false;
            }
        }

        public static bool Is<T>(this System.Enum type, T value) {
            try {
                return (int)(object)type == (int)(object)value;
            }
            catch {
                return false;
            }    
        }


        public static T Add<T>(this System.Enum type, T value) {
            try {
                return (T)(object)(((int)(object)type | (int)(object)value));
            }
            catch(Exception ex) {
                throw new ArgumentException(
                    string.Format(
                        "Could not append value from enumerated type '{0}'.",
                        typeof(T).Name
                        ), ex);
            }    
        }


        public static T Remove<T>(this System.Enum type, T value) {
            try {
                return (T)(object)(((int)(object)type & ~(int)(object)value));
            }
            catch (Exception ex) {
                throw new ArgumentException(
                    string.Format(
                        "Could not remove value from enumerated type '{0}'.",
                        typeof(T).Name
                        ), ex);
            }  
        }

    }
}

Затем они используются следующим образом

SomeType value = SomeType.Grapes;
bool isGrapes = value.Is(SomeType.Grapes); //true
bool hasGrapes = value.Has(SomeType.Grapes); //true

value = value.Add(SomeType.Oranges);
value = value.Add(SomeType.Apples);
value = value.Remove(SomeType.Grapes);

bool hasOranges = value.Has(SomeType.Oranges); //true
bool isApples = value.Is(SomeType.Apples); //false
bool hasGrapes = value.Has(SomeType.Grapes); //false
Автор: Hugoware Размещён: 06.01.2009 04:31

106 плюса

187622 Репутация автора

В .NET 4 теперь можно написать:

flags.HasFlag(FlagsEnum.Bit4)
Автор: Drew Noakes Размещён: 30.05.2011 05:48

22 плюса

647 Репутация автора

@Нарисовалась

Обратите внимание, что за исключением простейших случаев, Enum.HasFlag влечет за собой значительное снижение производительности по сравнению с написанием кода вручную. Рассмотрим следующий код:

[Flags]
public enum TestFlags
{
    One = 1,
    Two = 2,
    Three = 4,
    Four = 8,
    Five = 16,
    Six = 32,
    Seven = 64,
    Eight = 128,
    Nine = 256,
    Ten = 512
}


class Program
{
    static void Main(string[] args)
    {
        TestFlags f = TestFlags.Five; /* or any other enum */
        bool result = false;

        Stopwatch s = Stopwatch.StartNew();
        for (int i = 0; i < 10000000; i++)
        {
            result |= f.HasFlag(TestFlags.Three);
        }
        s.Stop();
        Console.WriteLine(s.ElapsedMilliseconds); // *4793 ms*

        s.Restart();
        for (int i = 0; i < 10000000; i++)
        {
            result |= (f & TestFlags.Three) != 0;
        }
        s.Stop();
        Console.WriteLine(s.ElapsedMilliseconds); // *27 ms*        

        Console.ReadLine();
    }
}

Более 10 миллионов итераций, метод расширения HasFlags занимает колоссальные 4793 мс, по сравнению с 27 мс для стандартной побитовой реализации.

Автор: Chuck Dee Размещён: 24.08.2011 07:51

2 плюса

126 Репутация автора

Это было вдохновлено использованием Sets в качестве индексаторов в Delphi, когда:

/// Example of using a Boolean indexed property
/// to manipulate a [Flags] enum:

public class BindingFlagsIndexer
{
  BindingFlags flags = BindingFlags.Default;

  public BindingFlagsIndexer()
  {
  }

  public BindingFlagsIndexer( BindingFlags value )
  {
     this.flags = value;
  }

  public bool this[BindingFlags index]
  {
    get
    {
      return (this.flags & index) == index;
    }
    set( bool value )
    {
      if( value )
        this.flags |= index;
      else
        this.flags &= ~index;
    }
  }

  public BindingFlags Value 
  {
    get
    { 
      return flags;
    } 
    set( BindingFlags value ) 
    {
      this.flags = value;
    }
  }

  public static implicit operator BindingFlags( BindingFlagsIndexer src )
  {
     return src != null ? src.Value : BindingFlags.Default;
  }

  public static implicit operator BindingFlagsIndexer( BindingFlags src )
  {
     return new BindingFlagsIndexer( src );
  }

}

public static class Class1
{
  public static void Example()
  {
    BindingFlagsIndexer myFlags = new BindingFlagsIndexer();

    // Sets the flag(s) passed as the indexer:

    myFlags[BindingFlags.ExactBinding] = true;

    // Indexer can specify multiple flags at once:

    myFlags[BindingFlags.Instance | BindingFlags.Static] = true;

    // Get boolean indicating if specified flag(s) are set:

    bool flatten = myFlags[BindingFlags.FlattenHierarchy];

    // use | to test if multiple flags are set:

    bool isProtected = ! myFlags[BindingFlags.Public | BindingFlags.NonPublic];

  }
}
Автор: Tony Tanzillo Размещён: 09.03.2012 10:09

8 плюса

563 Репутация автора

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

В .NET 4 HasFlagбыл добавлен метод, Enumкоторый помогает упростить пользовательский код, но, к сожалению, с ним много проблем.

  1. HasFlag не является типобезопасным, поскольку принимает любой тип аргумента значения перечисления, а не только данный тип перечисления.
  2. HasFlagнеоднозначно, проверяет ли он, имеет ли значение все или какие-либо из флагов, предоставленных аргументом значения перечисления. Это все кстати.
  3. HasFlag довольно медленный, так как требует бокса, который вызывает выделение ресурсов и, следовательно, сборку мусора.

Частично из-за ограниченной поддержки .NET перечислений флагов я написал библиотеку OSS Enums.NET, которая решает каждую из этих проблем и значительно облегчает работу с перечислениями флагов.

Ниже приведены некоторые операции, которые он предоставляет вместе с эквивалентными реализациями, использующими только .NET Framework.

Объединить флаги

.СЕТЬ             flags | otherFlags

Enums.NET flags.CombineFlags(otherFlags)


Удалить флаги

.СЕТЬ             flags & ~otherFlags

Enums.NET flags.RemoveFlags(otherFlags)


Общие флаги

.СЕТЬ             flags & otherFlags

Enums.NET flags.CommonFlags(otherFlags)


Переключить флаги

.СЕТЬ             flags ^ otherFlags

Enums.NET flags.ToggleFlags(otherFlags)


Имеет все флаги

.NET             (flags & otherFlags) == otherFlags илиflags.HasFlag(otherFlags)

Enums.NET flags.HasAllFlags(otherFlags)


Есть флаги

.СЕТЬ             (flags & otherFlags) != 0

Enums.NET flags.HasAnyFlags(otherFlags)


Получить флаги

.СЕТЬ

Enumerable.Range(0, 64)
  .Where(bit => ((flags.GetTypeCode() == TypeCode.UInt64 ? (long)(ulong)flags : Convert.ToInt64(flags)) & (1L << bit)) != 0)
  .Select(bit => Enum.ToObject(flags.GetType(), 1L << bit))`

Enums.NET flags.GetFlags()


Я пытаюсь включить эти улучшения в .NET Core и, возможно, в конечном итоге в полную версию .NET Framework. Вы можете проверить мое предложение здесь .

Автор: TylerBrinkley Размещён: 14.06.2017 05:27

0 плюса

8 Репутация автора

Для лучшей производительности и отсутствия мусора используйте это:

using System;
using T = MyNamespace.MyFlags;

namespace MyNamespace
{
    [Flags]
    public enum MyFlags
    {
        None = 0,
        Flag1 = 1,
        Flag2 = 2
    }

    static class MyFlagsEx
    {
        public static bool Has(this T type, T value)
        {
            return (type & value) == value;
        }

        public static bool Is(this T type, T value)
        {
            return type == value;
        }

        public static T Add(this T type, T value)
        {
            return type | value;
        }

        public static T Remove(this T type, T value)
        {
            return type & ~value;
        }
    }
}
Автор: Mark Bamford Размещён: 03.03.2019 08:19
Вопросы из категории :
32x32