【问题标题】:What is the internal logic for Enum HasFlag function implementationEnum HasFlag函数实现的内部逻辑是什么
【发布时间】:2020-05-07 01:24:47
【问题描述】:

有人可以帮我理解枚举类的 HasFlag 方法的内部逻辑吗? 让我先解释一下我的要求。 我已经创建了一个带有标志属性的枚举,然后使用 HasFlag() 函数从位标志值中获取选定的组合。 但在这里我的要求是不同的。我的数据库中有一个表,其中列出了不同的枚举值。结构如下。

EnumTypeID    EnumVal      EnumID     Description 
===========  ==========   =========  ================
   1           enum1          0         xxxxxxxxx
   1           enum2          1         xxxxxxxxx
   1           enum3          2         xxxxxxxxx
   2           enum4          0         xxxxxxxxx
   2           enum5          1         xxxxxxxxx

假设我有另一个表,它存储 EnumTypeID 1 的最终标志组合。所以该表列假设保存不同的组合,如

0 = Nothing selected
1 = enum1 selected
2 = enum2 selected
3 = enum1 & enum2 selected
4 = enum3 selected
5 = enum1 & enum3 selected
6 = enum2 & enum3 selected
7 = enum1 & enum2 & enum3 selected

================================================ ===============

现在我如何以编程方式(在 C# .net4.5 中)实现这一点。我需要首先查询第一个表并获取特定 EnumTypeID 的枚举列表。现在我需要从第二个表中获取所选标志的值(假设值为 5)。那我怎么能说基本上 enum1 & enum3 是通过代码选择的呢?

【问题讨论】:

  • 我不知道其他人,但我对你的问题感到非常困惑。您在任何地方都有实际的 C# 枚举吗?如果是这样,如果你能发布它真的会有所帮助......
  • 其实我并不想创建Enum,而是想使用Enum标志属性的概念。我的枚举将来自数据库。基于这些 enumIds 的值,我需要编写一些代码来动态创建 2 的幂值。然后我需要再次将其与数据库中的标志值进行比较。

标签: c# asp.net-mvc-3 enums enum-flags


【解决方案1】:

正如您在下面的链接中看到的,HasFlag 返回 thisInstance And flag = flag 表达式的结果

Enum.HasFlag

见备注部分

如果我正确地回答了您的问题,您需要这样的查询:

select * from SecondTable where FlagColumn & 5 = 5

【讨论】:

  • 感谢您的回答。我从您提到的链接中获得了帮助。
【解决方案2】:

如果我必须实现方法Enum.HasFlag,我会这样写。

public static bool HasFlag2(this Enum e, Enum flag)
{
    // Check whether the flag was given
    if (flag == null)
    {
        throw new ArgumentNullException("flag");
    }

    // Compare the types of both enumerations
    if (!e.GetType().IsEquivalentTo(flag.GetType()))
    {
        throw new ArgumentException(string.Format(
            "The type of the given flag is not of type {0}", e.GetType()),
            "flag");
    }

    // Get the type code of the enumeration
    var typeCode = e.GetTypeCode();

    // If the underlying type of the flag is signed
    if (typeCode == TypeCode.SByte || typeCode == TypeCode.Int16 || typeCode == TypeCode.Int32 || typeCode == TypeCode.Int64)
    {
        return (Convert.ToInt64(e) & Convert.ToInt64(flag)) != 0;
    }

    // If the underlying type of the flag is unsigned
    if (typeCode == TypeCode.Byte || typeCode == TypeCode.UInt16 || typeCode == TypeCode.UInt32 || typeCode == TypeCode.UInt64)
    {
        return (Convert.ToUInt64(e) & Convert.ToUInt64(flag)) != 0;
    }

    // Unsupported flag type
    throw new Exception(string.Format("The comparison of the type {0} is not implemented.", e.GetType().Name));
}

它使用AND 运算符执行二进制比较。更多信息here。 如果需要,您可以在 Visual Studio 中测试其行为,这是一种扩展方法。

希望对你有帮助。

编辑 2014-01-10

Enum 类型没有实现& 运算符,这使我们在尝试手动比较标志时更加努力。它们必须转换为枚举的底层类型(实现& 运算符)。

为了处理枚举的所有可能类型,我更新了我的代码。基本上,我们检索枚举的基础类型并根据它们是有符号还是无符号来转换它们。

【讨论】:

  • enum 不需要使用int 作为其底层表示;任何使用其他东西的方法都会失败。
  • @supercat:感谢您的评论,您是对的。我更新了我的帖子以考虑到这一点。
  • 如果我定义了一个枚举 [Flags]enum MyEnum{A=1, B=2, C=4, D=8} 然后 (MyEnum.B|MyEnum.C).HasFlag(MyEnum.C|MyEnum.D) 返回 false 而 (MyEnum.B|MyEnum.C).HasFlag2(MyEnum.C|MyEnum.D) 返回 true。这是因为 HasFlag 测试 (e&flag)==flag 而不是 (e&flag)!=0。很遗憾,因为我想要你的版本的行为:)
  • Enum.HasFlag 执行 a & b == b,而不是 a & b != 0。因此,如果传递了多个标志,它会检查是否包含所有标志,而不是其中任何一个.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-25
  • 2016-09-05
  • 2019-07-01
  • 1970-01-01
相关资源
最近更新 更多