对于我的生活,我不记得如何设置,删除,切换或测试位域中的位.要么我不确定,要么混淆它们,因为我很少需要这些.因此,"比特作弊表"会很好.
例如:
flags = flags | FlagsEnum.Bit4; // Set bit 4.
要么
if ((flags & FlagsEnum.Bit4)) == FlagsEnum.Bit4) // Is there a less verbose way?
您能举例说明所有其他常见操作,最好是使用[Flags]枚举的C#语法吗?
我在这些扩展上做了更多的工作 - 你可以在这里找到代码
我写了一些扩展方法,扩展了我经常使用的System.Enum ...我并没有声称它们是防弹的,但是他们帮助了...... 评论被删除了......
namespace Enum.Extensions { public static class EnumerationExtensions { public static bool Has(this System.Enum type, T value) { try { return (((int)(object)type & (int)(object)value) == (int)(object)value); } catch { return false; } } public static bool Is (this System.Enum type, T value) { try { return (int)(object)type == (int)(object)value; } catch { return false; } } public static T Add (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 (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
在.NET 4中,您现在可以编写:
flags.HasFlag(FlagsEnum.Bit4)
习惯用法是使用按位或等于运算符来设置位:
flags |= 0x04;
要清除一点,成语是按位使用和否定:
flags &= ~0x04;
有时你有一个标识你的位的偏移量,然后成语是使用这些与左移相结合:
flags |= 1 << offset; flags &= ~(1 << offset);
@Drew
请注意,除了最简单的情况外,与手动编写代码相比,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(); } }
超过1000万次迭代,HasFlags扩展方法需要高达4793 ms,而标准按位实现则为27 ms.
不幸的是,.NET的内置标志枚举操作非常有限.大多数时候,用户只能计算出按位运算逻辑.
在.NET 4中,HasFlag
添加了Enum
该方法有助于简化用户代码,但遗憾的是它存在许多问题.
HasFlag
不是类型安全的,因为它接受任何类型的枚举值参数,而不仅仅是给定的枚举类型.
HasFlag
是否检查该值是否具有枚举值参数提供的全部或任何标志是不明确的.顺便说一下.
HasFlag
是相当慢,因为它需要拳击,导致分配,从而更多的垃圾收集.
部分由于.NET对标志枚举的有限支持,我编写了OSS库Enums.NET,它解决了这些问题并使得处理标志枚举变得更加容易.
下面是它提供的一些操作以及仅使用.NET框架的等效实现.
结合旗帜.净 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.你可以在这里查看我的建议.
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))