【问题标题】:Right shift operator does not work in flags enum右移运算符在标志枚举中不起作用
【发布时间】:2021-02-09 20:01:16
【问题描述】:

我有以下带有标志属性的枚举:

[Flags]
public enum MyEnum
{
    None = 0,
    First = 1,
    Second= 2,
    Third= 4,
       .
       .
       .
    Unknown = All >> 1,
    All = ~None,
}

我希望Unknown 值是All 值之前的最后一个值。所以我认为右移运算符会完成这项工作,但是当我像这样将两个值打印到控制台时:

Console.WriteLine((int)MyEnum.All);
Console.WriteLine((int)MyEnum.Unknown);

它打印-1-1。 我在做什么错,如何修改代码以在 All 之前添加 Unknown

编辑:感谢大家的回答,我忽略了右移运算符执行算术移位并“将符号位传播到高阶空位位置”。最后我意识到我的方法无论如何都会给我错误的结果,因为MyEnum.Unknown.HasFlag(MyEnum.First); 会返回true,那将是不正确的行为。这个answer 为我指明了正确的方向,我将Unknown 设置为int.MinValue,这正是我想要完成的——我希望Unknown 与任何其他值一样,并且也是可能的最高值。现在我只是很尴尬,我之前没有考虑过这个......

【问题讨论】:

  • From Right-shift operator >>: "如果左操作数的类型为intlong,右移运算符执行算术 移位:值左侧操作数的最高有效位(符号位)被传播到高位空位位置。”
  • 为了完整起见,来自Enumeration types:“默认情况下,枚举成员的关联常量值为int类型;它们从零开始,按照定义文本顺序加一。”
  • Unknown = (int)unchecked(((uint)All) >> 1),

标签: c#


【解决方案1】:

您似乎希望All 成为0xFFFFFFFFUnknown 成为0x8000000,以便Unknown 包含在All 中。有趣的想法。也许0x7FFFFFFF0x8000000 会更有意义:

using System;
                    
public class Program
{
    [Flags]
    public enum MyEnum : uint
    {
    None = 0,
    First = 1,
    Second= 2,
    Third= 4, // ...
    Unknown = (uint)1 << 31, // Most-significant-bit.
    All = ~Unknown}

    public static void Main()
    {
        Console.WriteLine("All: " + ((uint)MyEnum.All).ToString("X"));
        Console.WriteLine("Unknown: " + ((uint)MyEnum.Unknown).ToString("X"));
    }
}

.NETfiddle.

【讨论】:

    【解决方案2】:

    枚举基于有符号整数,即int

    如果你使用任何整数,你会发现这种行为是完全正确的(从 C# 交互输出):

    > int i = 0;
    > int j = ~i;
    > j
    -1
    > int k = j >> 1;
    > k
    -1
    

    为了更深入的解释和理解,我建议阅读this SO post。它甚至得到了一位从事 C# 语言工作的人的回答 :)

    但是基线是:您所看到的是完全正确的并且以这种方式工作,因为枚举在下面是ints,除非您另有说明(您可以使用uint 而不是long):

    public enum LongEnum : long
    {
        //values
    }
    

    【讨论】:

    • 澄清你可以通过这样做覆盖默认的“int”行为public enum MyEnum : uint {...}
    • @Andy 是的,我只是在写那个:)
    • 嗯.. 如果我这样做:public enum MyEnum : uint {...} 我仍然会得到符号扩展行为(AllUnknown 最终等于 4294967295)。你想让高位为零吗?您可能想使用All &amp; 7FFF_FFFF 清除该位。
    【解决方案3】:

    也许它适合你:

      0     0x00000000     None
      1     0x00000001     First
      2     0x00000002     Second
      4     0x00000004     Third
     -2     0xFFFFFFFE     Unknown
     -1     0xFFFFFFFF     All
    

    代码:

    using System;
    
    [Flags]
    public enum MyEnum
    {
        None = 0,
        First = 1,
        Second= 2,
        Third= 4,
        Unknown = All << 1,
        All = ~None,
    }
    
    public class Example {
        public static void Main() {
            foreach (var value in Enum.GetValues(typeof(MyEnum))) {
                Console.WriteLine("{0,3}     0x{0:X8}     {1}",
                               (int) value, ((MyEnum) value));
            }   
        
       }
    }
    

    【讨论】:

      【解决方案4】:

      以下内容可能会有所帮助。 “全部”涵盖除最高有效位之外的所有位。最高有效位用于“未知”。

      [Flags]
      public enum MyEnum : uint
      {
          None = 0,
          First = 1,
          Second = 2,
          Third = 4,
          All = uint.MaxValue >> 1,
          Unknown = ~All,
      }
      

      【讨论】:

        【解决方案5】:

        好吧,右移当最高有效位设置为 1 时,&gt;&gt;intuint 的工作方式不同:

        int  : 1.... >> 1 == 11.... : sign bit (which is 1 here) propagates
        uint : 1.... >> 1 == 01.... : 0 added
        

        您想要 第二种 行为,这由uint 演示,所以让我们在右移时将All 转换为uint

        [Flags]
        public enum MyEnum
        {
            None = 0,
            ...
            Unknown = (int)unchecked(((uint)All) >> 1),
            All = ~None,
        }
        

        我不推荐public enum MyEnum : uint 声明,因为uint 不符合cls

        【讨论】:

          猜你喜欢
          • 2018-12-09
          • 1970-01-01
          • 2011-01-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-09
          相关资源
          最近更新 更多