Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
枚举上最常见的C#按位操作_C#_.net_Enums_Bit Manipulation_Flags - Fatal编程技术网

枚举上最常见的C#按位操作

枚举上最常见的C#按位操作,c#,.net,enums,bit-manipulation,flags,C#,.net,Enums,Bit Manipulation,Flags,就我的一生而言,我不记得如何设置、删除、切换或测试位字段中的位。要么我不确定,要么我把它们弄混了,因为我很少需要它们。所以有一张“小备忘单”就好了 例如: flags = flags | FlagsEnum.Bit4; // Set bit 4. 或 您能否给出所有其他常见操作的示例,最好是使用[Flags]枚举的C#语法?C++操作有:&^~(用于and、or、xor和not位操作)。同样有趣的是>>和习惯用法是使用按位或相等运算符设置位: flags |= 0x04; 要清除一点,习惯

就我的一生而言,我不记得如何设置、删除、切换或测试位字段中的位。要么我不确定,要么我把它们弄混了,因为我很少需要它们。所以有一张“小备忘单”就好了

例如:

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


您能否给出所有其他常见操作的示例,最好是使用[Flags]枚举的C#语法?

C++操作有:&^~(用于and、or、xor和not位操作)。同样有趣的是>>和习惯用法是使用按位或相等运算符设置位:

flags |= 0x04;
要清除一点,习惯用法是使用按位and和否定:

flags &= ~0x04;
有时,您有一个标识位的偏移量,习惯用法是将这些偏移量与左移位结合使用:

flags |= 1 << offset;
flags &= ~(1 << offset);

flags |=1C++语法,假设位0为LSB,假设flags为无符号长:

检查是否已设置:

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


flag |=(1UL要测试位,您将执行以下操作:
(假设标志为32位数字)

测试位:
if((flags & 0x08) == 0x08)
(如果设置了位4,则其为真) 向后切换(1-0或0-1):
将第4位重置为零:

我对这些扩展做了更多的工作-

flags = flags & 0xFFFFFF7F;
我写了一些扩展方法来扩展我经常使用的System.Enum…我并不是说它们是防弹的,但它们有帮助…删除了注释


在.NET 4中,您现在可以编写:

flags.HasFlag(FlagsEnum.Bit4)
@德鲁

注意到,除了在最简单的情况下,枚举HasGrand与手工编写代码相比,会带来很大的性能损失。请考虑下面的代码:

[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();
    }
}
[标志]
公共枚举测试标志
{
1=1,
二等于二,
三等于四,
四等于八,
五=16,
六=32,
七=64,
八=128,
九等于256,
十=512
}
班级计划
{
静态void Main(字符串[]参数)
{
TestFlags f=TestFlags.Five;/*或任何其他枚举*/
布尔结果=假;
秒表s=Stopwatch.StartNew();
对于(int i=0;i<10000000;i++)
{
结果|=f.HasFlag(TestFlags.Three);
}
s、 停止();
控制台。写入线(秒);//*4793毫秒*
s、 重启();
对于(int i=0;i<10000000;i++)
{
结果|=(f&TestFlags.Three)!=0;
}
s、 停止();
控制台写入线(秒);//*27毫秒*
Console.ReadLine();
}
}

超过1000万次迭代,HasFlags扩展方法所需时间高达4793毫秒,而标准按位实现所需时间为27毫秒。

这是受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];

  }
}

遗憾的是,.NET的内置标志枚举操作非常有限。大多数时间用户都没有弄清楚按位操作逻辑

在.NET4中,方法
HasFlag
被添加到
Enum
中,这有助于简化用户代码,但不幸的是,它存在许多问题

  • HasFlag
    不是类型安全的,因为它接受任何类型的枚举值参数,而不仅仅是给定的枚举类型
  • HasFlag
    在检查值是否包含枚举值参数提供的全部或任何标志时不明确。顺便说一下
  • HasFlag
    相当慢,因为它需要装箱,这会导致分配和更多的垃圾收集
  • 部分由于.NET对标志枚举的支持有限,我编写了OSS库,它解决了这些问题,并使处理标志枚举变得更加容易

    下面是它提供的一些操作以及它们仅使用.NET框架的等效实现

    联合旗帜 .NET
    标志|其他标志

    Enums.NET
    flags.CombineFlags(其他标志)


    撤除旗帜 .NET
    flags和~otherFlags

    Enums.NET
    flags.RemoveFlags(其他标志)


    共同旗帜 .NET
    标志和其他标志

    Enums.NET
    flags.CommonFlags(其他标志)


    切换标志 .NET
    标志^otherFlags

    Enums.NET
    flags.ToggleFlags(其他标志)


    有所有的旗帜 .NET
    (标志和其他标志)=其他标志
    标志.HasFlag(其他标志)

    Enums.NET
    flags.HasAllFlags(其他标志)


    有旗帜吗 .NET
    (标志和其他标志)!=0

    Enums.NET
    flags.HasAnyFlags(其他标志)


    拿旗子 .NET

    可枚举范围(0,64)
    
    .Where(bit=>((flags.GetTypeCode()==TypeCode.UInt64?(long)(ulong)flags:Convert.ToInt64(flags))&(1L Enum.ToObject(flags.GetType(),1L)要获得最佳性能和零垃圾,请使用以下选项:

    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;
            }
        }
    }
    

    我也发现这很有用-有什么想法我可以修改它,使它在任何基础类型上工作吗?这些扩展只是我的一天,我的一周,我的一个月,很可能是我的一年。谢谢大家!大家:一定要查看Hugoware链接到的更新。一组非常好的扩展。很遗憾,它们需要装箱,尽管我想不出一个替代方案它不使用装箱,非常简洁。即使是
    Enum
    上的新
    hasvag
    方法也需要装箱。@Drew:有关避免装箱的方法,请参阅:)问题与c#有关,而不是与c++有关。另一方面,c#使用相同的运算符:为了保护@workmad3,原始标记使用c和c+++1来指出这一点,尽管
    FlagsEnum
    是一个丑陋的名称。:)@吉姆,也许吧。这只是一个样本名称,正如原始问题中所使用的那样,因此您可以在代码中随意更改。我知道!但丑陋的名称就像IE6一样,可能永远不会消失:(@JimSchubert,同样,我只是从原始问题中复制了类型名称,以免混淆问题。这表明所有
    [标志]
    enum应该有多个名称,因此名称
    FlagsEnum
    的问题甚至比丑陋更严重。我也推荐。购买有点贵,但我相信Safari Online
    flags = flags ^ 0x08;
    flags = flags & 0xFFFFFF7F;
    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
    
    flags.HasFlag(FlagsEnum.Bit4)
    
    [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();
        }
    }
    
    /// 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];
    
      }
    }
    
    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))`
    
    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;
            }
        }
    }